WebApi 使用TOKEN+签名验证

3 篇文章 0 订阅
1 篇文章 0 订阅

1.基于Token令牌 + 签名的验证思路梳理

    客户端首先向服务端请求Token令牌,客户获取Token后计算对应的签名。签名由时间戳、随机数、Token令牌、参数拼接字符串四部分组成,客户端发送请求的时候需要带上对应的身份ID、时间戳、随机数和计算出的签名。

    服务端过滤器拦截请求,验证请求参数的合法性、是否过期,Token令牌是否合法、是否过期,全部通过后重新计算签名,与传递的签名参数对比,一致则执行对应的Api请求,否则返回错误消息。如果服务端计算的签名与传递的参数签名不一样,请求不合法(可能被篡改),为什么这么说呢,因为客户端与服务端拥有相同的签名计算方式,如果请求被修改,那么服务端计算的签名肯定与客户端计算的签名肯定不一致。

 

1.1 客户端请求Token令牌流程

    客户端请求Token的凭证是对应的身份ID,当然可以是其他的,这里假设用的是身份ID。

    (1)首先客户端向服务端发送获取Token令牌的请求,这个Token令牌是一个GUID码,生成后服务端会将其存在缓存中,当再次请求的时候会先从缓存中查找。请求Token令牌的代码:

        /// <summary>
        /// 根据用户名获取token
        /// </summary>
        /// <param name="companyid"></param>
        /// <returns></returns>
        public HttpResponseMessage GetToken(string companyid)
        {
            ResultMsg resultMsg = null;
            GetCompany();
            DataRow[] _drs = DtOmsCompany.Select(string.Format("Id='{0}' ", companyid));
            if (_drs.Length<1)
            {
                resultMsg = new ResultMsg((int)StatusCodeEnum.CompanyNull, StatusCodeEnum.CompanyNull.GetEnumText(), companyid);
                return HttpResponseExtension.toJson(JsonConvert.SerializeObject(resultMsg));
            }
            try
            {
                string id = "";

                //判断参数是否合法
                if (string.IsNullOrEmpty(companyid))
                {
                    resultMsg = new ResultMsg();
                    resultMsg.StatusCode = (int)StatusCodeEnum.ParameterError;
                    resultMsg.Info = StatusCodeEnum.ParameterError.GetEnumText();
                    resultMsg.Data = "";
                    Console.WriteLine(resultMsg.ToString());
                    return HttpResponseExtension.toJson(JsonConvert.SerializeObject(resultMsg));
                }

                //插入缓存
                Token token = (Token)HttpRuntime.Cache.Get(companyid);
                //Console.WriteLine(token.ToString());
                if (HttpRuntime.Cache.Get(companyid) == null)
                {
                    token = new Token();
                    token.CompanyId = companyid;
                    token.SignToken = Guid.NewGuid();
                    token.ExpireTime = DateTime.Now.AddDays(7);
                    //Console.WriteLine(resultMsg.ToString());
                    HttpRuntime.Cache.Insert(token.CompanyId, token, null, token.ExpireTime, TimeSpan.Zero);
                }

                //返回token信息
                resultMsg = new ResultMsg();
                resultMsg.StatusCode = (int)StatusCodeEnum.Success;
                resultMsg.Info = "成功获取Token";
                resultMsg.Data = token;
            }
            catch (Exception ex)
            {

                Console.WriteLine(ex.Message + "\t" + ex.StackTrace);
            }
            Console.WriteLine(resultMsg.ToString());
            return HttpResponseExtension.toJson(JsonConvert.SerializeObject(resultMsg));
        }

1.tokenApi是配置在webConfig中的接口Url

2.Parames字典对象用来封装参数的,因为请求Token时可能不止一个参数。

3.Parameter:是元组类型,元组可以承载任何的数据类型,这里用来接收GetQueryString方法返回的拼接字符串

4.token:客户端用来承载接口返回的Token令牌的类的实例,TokenResultMSg结构如下:

public class TokenResultMsg : HttpResponseMsg
        {
            public Tokens Result
            {
                get
                {
                    if (StatusCode == (int)StatusCodeEnum.Success)
                    {
                        return JsonConvert.DeserializeObject<Tokens>(Data.ToString());
                    }
                    return null;
                }
            }
        }

这个类实际是封装了一个Token类实例,因为Api接口返回的是Json数据类型,所以这里进行了反序列化。Token类结构在最上面,里面包含身份ID、 Token令牌、 过期时间三个属性,最后返回包含Token令牌的Token类给主程序。Token类结构如下:

 public class Token
    {
        /// <summary>
        /// 用户名
        /// </summary>
        public string CompanyId { get; set; }

        /// <summary>
        /// 用户名对应签名Token
        /// </summary>
        public Guid SignToken { get; set; }


        /// <summary>
        /// Token过期时间
        /// </summary>
        public DateTime ExpireTime { get; set; }
    }

上面调用了GetQueryString方法,这个方法是用来整理参数以及参数的拼接字符串,参数用来随URL传递,参数的拼接字符串用来生成对应的Sign签名,方法如下:

public static Tuple<string, string> GetQueryString(Dictionary<string, string> parames)
        {
            //第一步:把字典按key的字母顺序排序
            IDictionary<string, string> sortedParams = new SortedDictionary<string, string>(parames);
            IEnumerator<KeyValuePair<string, string>> dem = sortedParams.GetEnumerator();

            //第二部 把所有的名字和参数值串在一起
            StringBuilder query = new StringBuilder("");//签名字符串
            StringBuilder queryStr = new StringBuilder("");//url参数
            if (parames == null || parames.Count == 0)
            {
                return new Tuple<string, string>("", "");
            }

            while (dem.MoveNext())
            {
                string key = dem.Current.Key;
                string value = dem.Current.Value;
                if (!string.IsNullOrEmpty(key))
                {
                    query.Append(key).Append(value);
                    queryStr.Append("&").Append(key).Append("=").Append(value);
                }
            }
            return new Tuple<string, string>(query.ToString(), queryStr.ToString().Substring(1, queryStr.Length - 1));
        } 

(3)此时Url以及参数已经准备完成,之后调用了 Get 方法,发送获取Token的请求到WepApi接口,这里描述一下思路,请求的Get方法你可以做成单独的,也可以做成公共的,公共的是什么意思呢,就是这个Get方法不止可以用来请求Token令牌,请求的参数视安全程度决定,这里为了演示只传递了一个身份ID,在实际的操作过程中可以传递更多的验证数据,Get方法代码如下:

public class WebApiHelper
    {
        /// <summary>
        /// Post请求
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="url"></param>
        /// <param name="data"></param>
        /// <param name="companyid"></param>
        /// <returns></returns>
        public static T Post<T>(string url, string data, string companyid)
        {
            byte[] bytes = Encoding.UTF8.GetBytes(data);
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);

            string timeStamp = GetTimeStamp();
            string nonce = GetRandom();
            //加入头信息
            request.Headers.Add("companyid", companyid); //当前请求用户companyid
            request.Headers.Add("timestamp", timeStamp); //发起请求时的时间戳(单位:毫秒)
            request.Headers.Add("nonce", nonce); //随机数
            request.Headers.Add("signature", GetSignature(timeStamp, nonce, companyid, data)); //当前请求内容的数字签名

            //写数据
            request.Method = "POST";
            request.ContentLength = bytes.Length;
            request.ContentType = "application/json";
            Stream reqstream = request.GetRequestStream();
            reqstream.Write(bytes, 0, bytes.Length);

            //读数据
            request.Timeout = 300000;
            request.Headers.Set("Pragma", "no-cache");
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            Stream streamReceive = response.GetResponseStream();
            StreamReader streamReader = new StreamReader(streamReceive, Encoding.UTF8);
            string strResult = streamReader.ReadToEnd();

            //关闭流
            reqstream.Close();
            streamReader.Close();
            streamReceive.Close();
            request.Abort();
            response.Close();

            return JsonConvert.DeserializeObject<T>(strResult);
        }

        /// <summary>
        /// Get请求
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="webApi"></param>
        /// <param name="queryStr"></param>
        /// <param name="companyid"></param>
        /// <returns></returns>
        public static T Get<T>(string webApi, string query, string queryStr, string companyid, bool sign = true)
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(webApi + "?" + queryStr);
            string timeStamp = GetTimeStamp();
            string nonce = GetRandom();
            //加入头信息
            request.Headers.Add("companyid", companyid); //当前请求用户companyid
            request.Headers.Add("timestamp", timeStamp); //发起请求时的时间戳(单位:毫秒)
            request.Headers.Add("nonce", nonce); //发起请求时的时间戳(单位:毫秒)

            if (sign)
            {
                request.Headers.Add("signature", GetSignature(timeStamp, nonce, companyid, query)); //当前请求内容的数字签名
            }

            request.Method = "GET";
            request.ContentType = "application/json";
            request.Timeout = 90000;
            request.Headers.Set("Pragma", "no-cache");
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            Stream streamReceive = response.GetResponseStream();
            StreamReader streamReader = new StreamReader(streamReceive, Encoding.UTF8);
            string strResult = streamReader.ReadToEnd();

            streamReader.Close();
            streamReceive.Close();
            request.Abort();
            response.Close();

            return JsonConvert.DeserializeObject<T>(strResult);
        }



        /// <summary>
        /// 获取token
        /// </summary>
        /// <param name="userinfo"></param>
        /// <returns></returns>
        public static TokenResultMsg GetSignToken(string companyid)
        {
            string tokenApi = AppSettingsConfig.GetTokenApi;
            Dictionary<string, string> parames = new Dictionary<string, string>();
            parames.Add("companyid", companyid);
            Tuple<string, string> parameters = GetQueryString(parames);
            TokenResultMsg token = WebApiHelper.Get<TokenResultMsg>(tokenApi, parameters.Item1, parameters.Item2, companyid, false);
            return token;
        }

        /// <summary>
        /// 计算签名
        /// </summary>
        /// <param name="timeStamp"></param>
        /// <param name="nonce"></param>
        /// <param name="companyid"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        private static string GetSignature(string timeStamp, string nonce, string companyid, string data)
        {
            Token token = null;
            var resultMsg = GetSignToken(companyid);
            if (resultMsg != null)
            {
                if (resultMsg.StatusCode == (int)StatusCodeEnum.Success)
                {
                    token = resultMsg.Result;
                }
                else
                {
                    Console.WriteLine(resultMsg.ToString());
                    return resultMsg.ToString();
                    //throw new Exception(resultMsg.Data.ToString());
                }
            }
            else
            {
                Console.WriteLine(resultMsg.ToString());
                return resultMsg.ToString();
                //throw new Exception("token为null,公司编号为:" + companyid);
            }

            var hash = System.Security.Cryptography.MD5.Create();
            //拼接签名数据
            var signStr = timeStamp + nonce + companyid + token.SignToken.ToString() + data;
            //将字符串中字符按升序排序
            var sortStr = string.Concat(signStr.OrderBy(c => c));
            var bytes = Encoding.UTF8.GetBytes(sortStr);
            //使用MD5加密
            var md5Val = hash.ComputeHash(bytes);
            //把二进制转化为大写的十六进制
            StringBuilder result = new StringBuilder();
            foreach (var c in md5Val)
            {
                result.Append(c.ToString("X2"));
            }
            return result.ToString().ToUpper();
        }

        /// <summary>  
        /// 获取时间戳  
        /// </summary>  
        /// <returns></returns>  
        private static string GetTimeStamp()
        {
            TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
            return Convert.ToInt64(ts.TotalMilliseconds).ToString();
        }


        /// <summary>  
        /// 获取随机数
        /// </summary>  
        /// <returns></returns>  
        private static string GetRandom()
        {
            Random rd = new Random(DateTime.Now.Millisecond);
            int i = rd.Next(0, int.MaxValue);
            return i.ToString();
        }


        /// <summary>
        /// 拼接get参数
        /// </summary>
        /// <param name="parames"></param>
        /// <returns></returns>
        public static Tuple<string, string> GetQueryString(Dictionary<string, string> parames)
        {
            // 第一步:把字典按Key的字母顺序排序
            IDictionary<string, string> sortedParams = new SortedDictionary<string, string>(parames);
            IEnumerator<KeyValuePair<string, string>> dem = sortedParams.GetEnumerator();

            // 第二步:把所有参数名和参数值串在一起
            StringBuilder query = new StringBuilder("");  //签名字符串
            StringBuilder queryStr = new StringBuilder(""); //url参数
            if (parames == null || parames.Count == 0)
            {
                return new Tuple<string, string>("", "");
            }

            while (dem.MoveNext())
            {
                string key = dem.Current.Key;
                string value = dem.Current.Value;
                if (!string.IsNullOrEmpty(key))
                {
                    query.Append(key).Append(value);
                    queryStr.Append("&").Append(key).Append("=").Append(value);
                }
            }

            return new Tuple<string, string>(query.ToString(), queryStr.ToString().Substring(1, queryStr.Length - 1));
        }
    }

(4)当代码执行到HttpWebResponse response = (HttpWebResponse)request.GetResponse();时客户端发送请求发到Api接口,此时我们来看Api接口收到请求的处理程序:

public class ServiceController : ApiController
    {
        public DataTable DtOmsCompany;//所有接入项目信息
        public void GetCompany()
        {
            bool IsIntranetSvr = false;//是否部署在内网
                                       //File.AppendAllText(@"\log.txt", "BdcAppEx() " + DateTime.Now.ToString() + ";\r\n");

            初始化DtOmsCompany
            //if (DtOmsCompany != null)
            //    continue;
            string cacheKey = "BdcCache_DtOmsCompany".ToLower();
            //var cacheList = LeaRun.Cache.Factory.CacheFactory.Cache().GetCache<DataTable>(cacheKey);
            var cacheList = CacheHelper.GetCache(cacheKey) as DataTable;
            if (cacheList == null)
            {
                DtOmsCompany = new DataTable();
                string BaseDbString = Ck.Oms.Code.Configs.GetDBConnectionStrValue("BaseDb");
                DbHelperSQLP dbHelperBaseDb = new DbHelperSQLP(BaseDbString);
                DataTable dt = dbHelperBaseDb.Query(" SELECT  o.OrganizeId,o.EnCode,o.OrganizeCode,o.ShortName,o.FullName,c.* FROM  Base_Organize o,Company c WHERE o.OrganizeId=c.OrganizeId AND c.IsValid=1 AND c.IsValidTest=1 AND c.OrganizeId IS NOT NULL ; ").Tables[0];
                dt.Columns.Add("Conn", typeof(string));

                foreach (DataRow rows in dt.Rows) //开始循环赋值
                {
                    string dbip = "", dbport = "";
                    if (IsIntranetSvr)
                    {
                        dbip = rows["Ip"].ToString();
                        dbport = rows["Port"].ToString();
                    }
                    else
                    {
                        dbip = rows["IpOut"].ToString();
                        dbport = rows["PortOut"].ToString();
                    }
                    rows["Conn"] = string.Format("Server={0},{1};Initial Catalog={2};User ID={3};Password={4}", dbip, dbport, rows["DataBaseName"], rows["Account"], rows["Password"]);
                }
                DtOmsCompany = dt;


                //LeaRun.Cache.Factory.CacheFactory.Cache().WriteCache(DtOmsCompany, cacheKey);
                CacheHelper.SetCache(cacheKey, DtOmsCompany, 900);
            }
            else
            {
                DtOmsCompany = cacheList;
            }
        }
        /// <summary>
        /// 根据用户名获取token
        /// </summary>
        /// <param name="companyid"></param>
        /// <returns></returns>
        public HttpResponseMessage GetToken(string companyid)
        {
            ResultMsg resultMsg = null;
            GetCompany();
            DataRow[] _drs = DtOmsCompany.Select(string.Format("Id='{0}' ", companyid));
            if (_drs.Length<1)
            {
                resultMsg = new ResultMsg((int)StatusCodeEnum.CompanyNull, StatusCodeEnum.CompanyNull.GetEnumText(), companyid);
                return HttpResponseExtension.toJson(JsonConvert.SerializeObject(resultMsg));
            }
            try
            {
                string id = "";

                //判断参数是否合法
                if (string.IsNullOrEmpty(companyid))
                {
                    resultMsg = new ResultMsg();
                    resultMsg.StatusCode = (int)StatusCodeEnum.ParameterError;
                    resultMsg.Info = StatusCodeEnum.ParameterError.GetEnumText();
                    resultMsg.Data = "";
                    Console.WriteLine(resultMsg.ToString());
                    return HttpResponseExtension.toJson(JsonConvert.SerializeObject(resultMsg));
                }

                //插入缓存
                Token token = (Token)HttpRuntime.Cache.Get(companyid);
                //Console.WriteLine(token.ToString());
                if (HttpRuntime.Cache.Get(companyid) == null)
                {
                    token = new Token();
                    token.CompanyId = companyid;
                    token.SignToken = Guid.NewGuid();
                    token.ExpireTime = DateTime.Now.AddDays(7);
                    //Console.WriteLine(resultMsg.ToString());
                    HttpRuntime.Cache.Insert(token.CompanyId, token, null, token.ExpireTime, TimeSpan.Zero);
                }

                //返回token信息
                resultMsg = new ResultMsg();
                resultMsg.StatusCode = (int)StatusCodeEnum.Success;
                resultMsg.Info = "成功获取Token";
                resultMsg.Data = token;
            }
            catch (Exception ex)
            {

                Console.WriteLine(ex.Message + "\t" + ex.StackTrace);
            }
            Console.WriteLine(resultMsg.ToString());
            return HttpResponseExtension.toJson(JsonConvert.SerializeObject(resultMsg));
        }
    }

 

public class DataManipulateController : ApiController
    {
        /// <summary>
        /// 数据接入
        /// </summary>
        /// <param name="token">授权码</param>
        /// <param name="companyid">经重新编码的组织机构Id(非公司工商登记代码,非在线监测中companyId)</param>
        /// <param name="typename">默认:"";环保:EFF_Real|EFF_Min|EFF_Hour|EFF_Day|EXH_Real|EXH_Min|EXH_Hour|EXH_Day;安全:</param>
        /// <param name="equipmentcode">设备代码Id,即为PointId,同一公司设备Id惟一</param>
        /// <param name="datetime">监测时间</param>
        /// <param name="dataJson">监测数据</param>
        /// <returns>成功插入数据记录数</returns>
        [HttpPost]
        public HttpResponseMessage DataUpLoad(monitordata mdata)
        {
            bool isIntranetSvr = bool.Parse(Config.GetValue("IsIntranetSvr"));
            BdcAppEx bdcAppEx = new BdcAppEx(isIntranetSvr);
            string companyid = mdata.companyid;
            string equipmentcode = mdata.equipmentcode;
            string surveytypecode = mdata.surveytypecode;
            string datetime = mdata.datetime;
            string data = mdata.datas.ToJson();
            object result = bdcAppEx.SetPutInData(companyid, equipmentcode, datetime, surveytypecode, data);
            int intt = 0;
            if (int.TryParse(result.ToString(), out intt))
            {
                ResultMsg resultMsg = null;
                resultMsg = new ResultMsg();
                resultMsg.StatusCode = (int)StatusCodeEnum.Success;
                resultMsg.Info = StatusCodeEnum.Success.GetEnumText();
                resultMsg.Data = mdata;
                return HttpResponseExtension.toJson(JsonConvert.SerializeObject(resultMsg));
                
            }
            else
            {
                ResultMsg resultMsg = null;
                resultMsg = new ResultMsg();
                resultMsg.StatusCode = (int)StatusCodeEnum.DBInsertError;
                resultMsg.Info = StatusCodeEnum.DBInsertError.GetEnumText();
                resultMsg.Data = mdata;
                return HttpResponseExtension.toJson(JsonConvert.SerializeObject(resultMsg));
            }

        }
    }

1.2 发送数据请求完整描述

     在客户端得到Token令牌之后每次请求都需要带上它,当然,只有Token令牌还是不够的,还需要编码的签名。签名由4个部分组成:时间戳、随机数、Token令牌、数据参数,编码的方式如下,首先将这四部分进行拼接字符串,然后将字符串中字符按照升序排序,之后转换为二进制数据流,然后进行MD5哈希加密,MD5是哈希加密的一种,接着循环遍历加密后的二进制字节流,这个时候字节流的长度时128位的,为了使用方便和节约网络传输流量我们需要把它转化为16进制的字符串,最后将所有的字符串转换为大写。至此,加密签名完成。生成Signature签名的代码如下:

public static string GetSignature(string timeStamp, string nonce, int staffId, string data)
        {
            Tokens token = null;
            var resultMsg = GetSignToken(staffId);
            if (resultMsg != null)
            {
                if (resultMsg.StatusCode == (int)StatusCodeEnum.Success)
                {
                    token = resultMsg.Result;
                }
                else
                {
                    throw new Exception(resultMsg.Data.ToString());
                }
            }
            else
            {
                throw new Exception("token为null,员工编号为:" + staffId);
            }

            var hash = System.Security.Cryptography.MD5.Create();
            //拼接签名数据
            var signStr = timeStamp + nonce + staffId + token.SignToken.ToString() + data;
            //将字符串中的字符按升序排序
            var sortStr = string.Concat(signStr.OrderBy(c => c));
            var bytes = Encoding.UTF8.GetBytes(sortStr);
            //使用MD5加密
            var md5Val = hash.ComputeHash(bytes);
            //把二进制转化为大写的十六进制
            StringBuilder result = new StringBuilder();
            foreach (var v in md5Val)
            {
                result.Append(v.ToString("X2"));
            }
            return result.ToString().ToUpper();
        } 

在发送数据请求的时候,需要传递四个参数,时间戳(用来判断请求是否过期)、随机数(用来强化请求的安全性)、身份ID(服务端用来查询对应的Token令牌)、Signature签名。

    那么服务端应该怎么验证用户的请求是否合法呢?服务端通过一个全局的过滤器(Filter)来拦截所有的客户端请求(不包含请求Token令牌),过滤器拦截到请求后首先判断请求方式,根据不同的请求方式获取请求中所有的参数(比如Get是QueryString,Post是InputStream),然后通过参数名称(key)得到参数的值(value),然后对参数进行相应的验证(是否为空或null),通过TimeSpan时间戳判断请求是否过期,如果过期则返回对应的错误信息;通过身份ID查询缓存中的Token令牌,与参数中令牌对比是否正确,如果验证都通过则对最后的签名做验证。

     服务端验证签名的方式是这样的,使用与客户端计算签名同样的算法,重新计算签名字符串,然后与请求中的前民字符串做对比.

public class ApiSecurityFilter : ActionFilterAttribute
    {
        public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)
        {
            ResultMsg resultMsg = null;
            var request = actionContext.Request;
            string method = request.Method.Method;
            string companyid = String.Empty, timestamp = string.Empty, nonce = string.Empty, signature = string.Empty;


            if (request.Headers.Contains("companyid"))
            {
                companyid = HttpUtility.UrlDecode(request.Headers.GetValues("companyid").FirstOrDefault());
            }
            if (request.Headers.Contains("timestamp"))
            {
                timestamp = HttpUtility.UrlDecode(request.Headers.GetValues("timestamp").FirstOrDefault());
            }
            if (request.Headers.Contains("nonce"))
            {
                nonce = HttpUtility.UrlDecode(request.Headers.GetValues("nonce").FirstOrDefault());
            }

            if (request.Headers.Contains("signature"))
            {
                signature = HttpUtility.UrlDecode(request.Headers.GetValues("signature").FirstOrDefault());
            }

            //GetToken方法不需要进行签名验证
            if (actionContext.ActionDescriptor.ActionName == "GetToken")
            {
                if (string.IsNullOrEmpty(companyid) || string.IsNullOrEmpty(timestamp) || string.IsNullOrEmpty(nonce))
                {
                    resultMsg = new ResultMsg();
                    resultMsg.StatusCode = (int)StatusCodeEnum.ParameterError;
                    resultMsg.Info = StatusCodeEnum.ParameterError.GetEnumText();
                    resultMsg.Data = "";
                    actionContext.Response = HttpResponseExtension.toJson(JsonConvert.SerializeObject(resultMsg));
                    base.OnActionExecuting(actionContext);
                    return;
                }
                else
                {
                    base.OnActionExecuting(actionContext);
                    return;
                }
            }


            //判断请求头是否包含以下参数
            if (string.IsNullOrEmpty(companyid) || string.IsNullOrEmpty(timestamp) || string.IsNullOrEmpty(nonce) || string.IsNullOrEmpty(signature))
            {
                resultMsg = new ResultMsg();
                resultMsg.StatusCode = (int)StatusCodeEnum.ParameterError;
                resultMsg.Info = StatusCodeEnum.ParameterError.GetEnumText();
                resultMsg.Data = "";
                actionContext.Response = HttpResponseExtension.toJson(JsonConvert.SerializeObject(resultMsg));
                base.OnActionExecuting(actionContext);
                return;
            }

            //判断timespan是否有效
            double ts1 = 0;
            double ts2 = (DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0)).TotalMilliseconds;
            bool timespanvalidate = double.TryParse(timestamp, out ts1);
            double ts = ts2 - ts1;
            bool falg = ts > int.Parse(WebSettingsConfig.UrlExpireTime) * 1000;
            if (falg || (!timespanvalidate))
            {
                resultMsg = new ResultMsg();
                resultMsg.StatusCode = (int)StatusCodeEnum.URLExpireError;
                resultMsg.Info = StatusCodeEnum.URLExpireError.GetEnumText();
                resultMsg.Data = "";
                actionContext.Response = HttpResponseExtension.toJson(JsonConvert.SerializeObject(resultMsg));
                base.OnActionExecuting(actionContext);
                return;
            }


            //判断token是否有效
            Token token = (Token)HttpRuntime.Cache.Get(companyid.ToString());
            string signtoken = string.Empty;
            if (HttpRuntime.Cache.Get(companyid.ToString()) == null)
            {
                resultMsg = new ResultMsg();
                resultMsg.StatusCode = (int)StatusCodeEnum.TokenInvalid;
                resultMsg.Info = StatusCodeEnum.TokenInvalid.GetEnumText();
                resultMsg.Data = "";
                actionContext.Response = HttpResponseExtension.toJson(JsonConvert.SerializeObject(resultMsg));
                base.OnActionExecuting(actionContext);
                return;
            }
            else
            {
                signtoken = token.SignToken.ToString();
            }

            //根据请求类型拼接参数
            NameValueCollection form = HttpContext.Current.Request.QueryString;
            string data = string.Empty;
            switch (method)
            {
                case "POST":
                    Stream stream = HttpContext.Current.Request.InputStream;
                    string responseJson = string.Empty;
                    StreamReader streamReader = new StreamReader(stream);
                    data = streamReader.ReadToEnd();
                    break;
                case "GET":
                    //第一步:取出所有get参数
                    IDictionary<string, string> parameters = new Dictionary<string, string>();
                    for (int f = 0; f < form.Count; f++)
                    {
                        string key = form.Keys[f];
                        parameters.Add(key, form[key]);
                    }

                    // 第二步:把字典按Key的字母顺序排序
                    IDictionary<string, string> sortedParams = new SortedDictionary<string, string>(parameters);
                    IEnumerator<KeyValuePair<string, string>> dem = sortedParams.GetEnumerator();

                    // 第三步:把所有参数名和参数值串在一起
                    StringBuilder query = new StringBuilder();
                    while (dem.MoveNext())
                    {
                        string key = dem.Current.Key;
                        string value = dem.Current.Value;
                        if (!string.IsNullOrEmpty(key))
                        {
                            query.Append(key).Append(value);
                        }
                    }
                    data = query.ToString();
                    break;
                default:
                    resultMsg = new ResultMsg();
                    resultMsg.StatusCode = (int)StatusCodeEnum.HttpMehtodError;
                    resultMsg.Info = StatusCodeEnum.HttpMehtodError.GetEnumText();
                    resultMsg.Data = "";
                    actionContext.Response = HttpResponseExtension.toJson(JsonConvert.SerializeObject(resultMsg));
                    base.OnActionExecuting(actionContext);
                    return;
            }

            bool result = SignExtension.Validate(timestamp, nonce, companyid, signtoken, data, signature);
            if (!result)
            {
                resultMsg = new ResultMsg();
                resultMsg.StatusCode = (int)StatusCodeEnum.HttpRequestError;
                resultMsg.Info = StatusCodeEnum.HttpRequestError.GetEnumText();
                resultMsg.Data = "";
                actionContext.Response = HttpResponseExtension.toJson(JsonConvert.SerializeObject(resultMsg));
                base.OnActionExecuting(actionContext);
                return;
            }
            else
            {
                base.OnActionExecuting(actionContext);
            }
        }
        public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
        {
            base.OnActionExecuted(actionExecutedContext);
        }

    }

参考http://www.cnblogs.com/MR-YY/p/5972380.html

根据自己需求做了部分改动

https://github.com/whuxxie/WebApiToken

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值