zoukankan      html  css  js  c++  java
  • Asp.net中接口签名与验签常用方法

    现在在程序开发中经常会用到第三方功能或数据,当我们调取第三方接口时,首先要做的就是要按照他们的规则进行验签通过后才可去使用。这也是出于安全方面的考虑,谁都不想自己的东西在网络中“裸奔”,哈哈。经常用的第三方如微信支付,第三方登录,支付宝支付等当然还有一些短信接口,身份验证接口等,而我们自己的程序对外开放时也会经常用到如自己写的Webapi接口等。下面就说一下常用的签名,验签的方式。

    _appId:应用唯一标识

    _appKey:加密key,用来校验应用的合法化

    一,签名工具类

    public class SignUtils
    {
    //编码格式
    private static string inputCharset = "utf-8";
    
    /// <summary>
    /// 签名字符串
    /// </summary>
    /// <param name="prestr">需要签名的字符串</param>
    /// <param name="key">密钥</param>
    /// <returns>签名结果</returns>
    public static string Sign(string prestr, string key)
    {
    StringBuilder sb = new StringBuilder(32);
    
    prestr = prestr + key;
    
    MD5 md5 = new MD5CryptoServiceProvider();
    byte[] t = md5.ComputeHash(Encoding.GetEncoding(inputCharset).GetBytes(prestr));
    for (int i = 0; i < t.Length; i++)
    {
    sb.Append(t[i].ToString("x").PadLeft(2, '0'));
    }
    
    return sb.ToString();
    }
    
    /// <summary>
    /// 验证签名
    /// </summary>
    /// <param name="prestr">需要签名的字符串</param>
    /// <param name="sign">签名结果</param>
    /// <param name="key">密钥</param>
    /// <returns>验证结果</returns>
    public static bool Verify(string prestr, string sign, string key)
    {
    string mysign = Sign(prestr, key);
    if (mysign == sign)
    {
    return true;
    }
    return false;
    }
    
    /// <summary>
    /// 生成请求时的签名
    /// </summary>
    /// <param name="sPara">请求给支付宝的参数数组</param>
    /// <param name="key"></param>
    /// <returns>签名结果</returns>
    public static string BuildSign(Dictionary<string, string> sPara, string key)
    {
    //把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
    string prestr = CreateLinkString(sPara);
    
    //把最终的字符串签名,获得签名结果
    var mysign = Sign(prestr, key);
    return mysign;
    }
    /// <summary>
    /// 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
    /// </summary>
    /// <param name="dicArray">需要拼接的数组</param>
    /// <returns>拼接完成以后的字符串</returns>
    public static string CreateLinkString(Dictionary<string, string> dicArray)
    {
    StringBuilder prestr = new StringBuilder();
    foreach (KeyValuePair<string, string> temp in dicArray)
    {
    prestr.Append(temp.Key + "=" + temp.Value + "&");
    }
    
    //去掉最後一個&字符
    int nLen = prestr.Length;
    prestr.Remove(nLen - 1, 1);
    
    return prestr.ToString();
    }
    
    /// <summary>
    /// 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串,并对参数值做urlencode
    /// </summary>
    /// <param name="dicArray">需要拼接的数组</param>
    /// <param name="code">字符编码</param>
    /// <returns>拼接完成以后的字符串</returns>
    public static string CreateLinkStringUrlencode(Dictionary<string, string> dicArray, Encoding code)
    {
    StringBuilder prestr = new StringBuilder();
    foreach (KeyValuePair<string, string> temp in dicArray)
    {
    prestr.Append(temp.Key + "=" + HttpUtility.UrlEncode(temp.Value, code) + "&");
    }
    //去掉最後一個&字符
    int nLen = prestr.Length;
    prestr.Remove(nLen - 1, 1);
    return prestr.ToString();
    }
    
    /// <summary>
    /// 除去数组中的空值和签名参数并以字母a到z的顺序排序
    /// </summary>
    /// <param name="dicArrayPre">过滤前的参数组</param>
    /// <returns>过滤后的参数组</returns>
    public static Dictionary<string, string> FilterPara(SortedDictionary<string, string> dicArrayPre)
    {
    Dictionary<string, string> dicArray = new Dictionary<string, string>();
    foreach (KeyValuePair<string, string> temp in dicArrayPre)
    {
    if (temp.Key.ToLower() != "sign" && !string.IsNullOrEmpty(temp.Value))
    {
    dicArray.Add(temp.Key, temp.Value);
    }
    }
    return dicArray;
    }
    View Code

    一,签名

    将传递参数放到SortedDictionary中进行操作

    var dic = new SortedDictionary<string, string>();
                var parameters = context.ApiActionDescriptor.Parameters;
                foreach (var apiParameterDescriptor in parameters)
                {
                    var value = apiParameterDescriptor.Value;
                    if (value.GetType() != typeof(string) && value.GetType() != typeof(int)&&value.GetType()!=typeof(long))
                    {
                        var properties = value.GetType().GetProperties();
                        foreach (var propertyInfo in properties)
                        {
                            var val = value.GetType().GetProperty(propertyInfo.Name)?.GetValue(value);
                            if (val != null)
                            {
                                dic.Add(propertyInfo.Name, val.ToString());
                            }
                        }
                    }
                    else
                    {
                        dic.Add(apiParameterDescriptor.Name, apiParameterDescriptor.Value.ToString());
                    }
    
                }
                dic.Add("appid", _appId);
                //计算sign
    
                var sortDic = SignUtils.FilterPara(dic);
                var newsign = SignUtils.BuildSign(sortDic, _appKey);
                context.RequestMessage.AddUrlQuery("appid", _appId);
                context.RequestMessage.AddUrlQuery("sign", newsign);
    View Code

    二,验签

    Webapi中验签代码

     protected override void HandleUnauthorizedRequest(HttpActionContext actionContext)
            {
    
                //禁用ajax请求
                var request = HttpContext.Current.Request;
    
                var headers = request.Headers;
                if (headers.AllKeys.Contains("X-Requested-With") && headers["X-Requested-With"] == "XMLHttpRequest")
                {
                    Failed(actionContext, ResultMessage.Error("不支持ajax请求"));
                    return;
                }
    
                //获取参数
                var dic = new SortedDictionary<string, string>();
                var streamReader = new StreamReader(request.InputStream);
                var result = streamReader.ReadToEnd();
    
                if (!string.IsNullOrWhiteSpace(result))
                {
                    var value = JsonConvert.DeserializeObject<JObject>(result);
                    foreach (var property in value.Properties())
                    {
                        dic.Add(property.Name, value.GetValue(property.Name).ToString());
                    }
                }
    
                if (request.Form.AllKeys.Length > 0)
                {
                    foreach (var paramKey in request.Form.AllKeys)
                    {
                        dic.Add(paramKey, request.Form[paramKey]);
                    }
                }
                if (request.QueryString.AllKeys.Length > 0)
                {
                    foreach (var paramKey in request.QueryString.AllKeys)
                    {
                        dic.Add(paramKey, request.QueryString[paramKey]);
                    }
                }
    
                ////验签
                if (!CheckSign(actionContext, dic))
                {
                    //验签失败
                }
            }
    
            /// <summary>
            /// 定义HttpResponseMessage
            /// </summary>
            /// <param name="actionContext">HttpActionContext</param>
            /// <param name="result">ResultMessage api结果返回类型</param>
            private void Failed(HttpActionContext actionContext, ResultMessage result)
            {
                actionContext.Response = actionContext.Response ?? new HttpResponseMessage();
                actionContext.Response.Content = new StringContent(JsonConvert.SerializeObject(result), Encoding.UTF8, "application/json");
            }
    
            /// <summary>
            /// 验签
            /// </summary>
            /// <returns>成功返回true</returns>
            private bool CheckSign(HttpActionContext actionContext, SortedDictionary<string, string> dic)
            {
                var appKey = ConfigHelper.GetConfigString("apiAppKey");
                //检查appid
                if (!CheckKey(actionContext, dic, "appid", out var appId))
                {
                    return false;
                }
    
    
                /*
                 * 此处直接声明了一个AppInfo的对象,实际开发中,要根据appId获取对应的appInfo信息,如下:
                 * var appInfo= appInfoService.GetAppInfo(appId);
                 */
                //var appInfo = _appInfoService.GetAppInfo(appId);
                //if (appInfo == null)
                //{
                //    Failed(actionContext, ResultMessage.Error(ResultEnum.AppNotExists));
                //    return false;
                //}
                //检查sign
                if (!CheckKey(actionContext, dic, "sign", out var sign))
                {
                    return false;
                }
                dic.Remove("sign");
    
                //计算sign
                var sortDic = SignUtils.FilterPara(dic);
                //var newsign = SignUtils.BuildSign(sortDic, appInfo.AppKey);
                var newsign = SignUtils.BuildSign(sortDic, appKey);
                //zKmxa_vyJHHUfNGoF85hXHSS5mq3tfwEYjyLMxiMCvo
                if (newsign != sign)
                {
                    Failed(actionContext, ResultMessage.Error(ResultEnum.InvalidSign));
                    return false;
                }
                return true;
            }
    
            /// <summary>
            /// 检查key
            /// </summary>
            /// <returns></returns>
            private bool CheckKey(HttpActionContext actionContext, SortedDictionary<string, string> dic, string key, out string value)
            {
                value = null;
                if (!dic.ContainsKey(key))
                {
                    Failed(actionContext, ResultMessage.ErrorFormat(ResultEnum.LossRequiredParams, key));
                    return false;
                }
                value = dic[key];
                if (string.IsNullOrEmpty(value))
                {
                    Failed(actionContext, ResultMessage.ErrorFormat(ResultEnum.InvalidParams, key));
                    return false;
                }
    
                return true;
            }
    View Code
  • 相关阅读:
    分支管理和自动化部署需求
    swiper 的左右箭头放到外面
    使用Foxmail登录阿里企业邮箱(钉钉邮箱)
    正则表达式 把所有的花引号替换为直引号 把字符串中所有单词的首字母都转换为大写
    react中getDerivedStateFromProps和componentDidUpdate配合使用
    model进阶
    cooke和session
    Django基础四之模板系统
    Django基础三之视图函数
    Django基础二之URL路由系统
  • 原文地址:https://www.cnblogs.com/MrLiu90/p/9875090.html
Copyright © 2011-2022 走看看