zoukankan      html  css  js  c++  java
  • 常用API接口签名验证参考

     

     

    项目中常用的API接口签名验证方法:

    1. 给app分配对应的key、secret
    2. Sign签名,调用API 时需要对请求参数进行签名验证,签名方式如下:
      a. 按照请求参数名称将所有请求参数按照字母先后顺序排序得到:keyvaluekeyvalue...keyvalue  字符串如:将arong=1,mrong=2,crong=3 排序为:arong=1, crong=3,mrong=2  然后将参数名和参数值进行拼接得到参数字符串:arong1crong3mrong2;
      b. 将secret加在参数字符串的头部后进行MD5加密 ,加密后的字符串需大写。即得到签名Sign;

    大致处理过程

    // 用户验证、判断key是否存在,同时查询出对应的secret用于验证;

    ....

    // 验证签名,根据算法将参数进行签名得到sign与参数中的sign进行对比;

    ....

    // 插叙数据获取列表

    如下图

    代码里

    app调用:http://api.test.com/getproducts?key=app_key&sign=BCC7C71CF93F9CDBDB88671B701D8A35&参数1=value1&参数2=value2.......
    注:secret 仅作加密使用, 为了保证数据安全请不要在请求参数中使用。

    请求的唯一性: 为了防止别人重复使用请求参数问题,我们需要保证请求的唯一性,就是对应请求只能使用一次,这样就算别人拿走了请求的完整链接也是无效的。
    唯一性的实现:在如上的请求参数中,我们加入时间戳 :timestamp(yyyyMMddHHmmss),同样,时间戳作为请求参数之一,也加入sign算法中进行加密。

    下面提供2个签名验证的方法:时间戳注意加入及验证的处理

    1、OpenId签名及验证

    复制代码
            /// <summary>
            /// 生成Code
            /// </summary>
            /// <param name="openid">openid</param>
            /// <param name="key">向谁跳传谁规定的key</param>
            /// <returns></returns>
            public static string MakeCode(string openid, string key)
            {
                DateTime time = DateTime.Now;
                string data = time.ToString("dd") + "_" + openid + "_" + time.ToString("yyyy") + "_" + key + "_" + time.ToString("MM");
                MD5 md5 = new MD5CryptoServiceProvider();
                byte[] result = Encoding.Default.GetBytes(data);
                byte[] output = md5.ComputeHash(result);
                data = BitConverter.ToString(output).Replace("-", "").ToLower();
                SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider();
                byte[] bytes = sha1.ComputeHash(Encoding.ASCII.GetBytes(data));//"596d42faf5710b35c7ea0f0a9600ee31"  F69D39E1CA07FC23C1CE62F549E9D5B9780
                //转16进制 清除前面0
                StringBuilder strB = new StringBuilder();
                for (int i = 0; i < bytes.Length; i++)
                {
                    string strX2 = bytes[i].ToString("X2");
                    if (strX2.Substring(0, 1) == "0")
                    {
                        strX2 = strX2.Substring(1, 1);
                    }
                    strB.Append(strX2);
                }
                return strB.ToString();
            }
            /// <summary>
            /// Code验证
            /// </summary>
            /// <param name="openid">openid</param>
            /// <param name="code">待验证的数据</param>
            /// <param name="key">自己系统规定的key</param>
            /// <returns></returns>
            public static bool ValidateCode(string openid, string code, string key)
            {
                string signedData = MakeCode(openid, key);
                return code.Equals(signedData, StringComparison.OrdinalIgnoreCase);
            }
    复制代码

    2、请求参数签名及验证

    复制代码
            /// <summary>
            /// 给请求签名
            /// </summary>
            /// <param name="parameters">所有字符型的请求参数</param>
            /// <param name="secret">签名密钥</param>
            /// <param name="qhs">是否前后都加密进行签名</param>
            /// <returns></returns>
            public string SignRequest(IDictionary<string, string> parameters, string secret, bool qhs)
            {
                // 第一步:把字典按Key的字母顺序排序
                IDictionary<string, string> sortedParams = new SortedDictionary<string, string>(parameters);
                IEnumerator<KeyValuePair<string, string>> dem = sortedParams.GetEnumerator();
                // 第二步:把所有参数名和参数值串在一起
                StringBuilder query = new StringBuilder(secret);
                while (dem.MoveNext())
                {
                    string key = dem.Current.Key;
                    string value = dem.Current.Value;
                    if (!string.IsNullOrWhiteSpace(key))//!string.IsNullOrWhiteSpace(value) 空值也加入计算??
                    {
                        query.Append(key).Append(value);
                    }
                }
                if (qhs)
                {
                    query.Append(secret);
                }
                // 第三部:使用md5运算
                MD5 md5 = MD5.Create();
                byte[] bytes = md5.ComputeHash(Encoding.UTF8.GetBytes(query.ToString()));
                // 第四部:把二进制转为大写的十六进制
                StringBuilder result = new StringBuilder();
                for (int i = 0; i < bytes.Length; i++)
                {
                    result.Append(bytes[i].ToString("X2"));
                }
                return result.ToString();
            }
    
            /// <summary>
            /// 验证签名
            /// </summary>
            /// <returns></returns>
            public bool ValidateSign(string secret)
            {
                string method = HttpContext.Current.Request.HttpMethod;
                System.Collections.Specialized.NameValueCollection form = HttpContext.Current.Request.QueryString;
                switch (method)
                {
                    case "POST":
                        form = HttpContext.Current.Request.Form;
                        break;
                    case "GET":
                        form = HttpContext.Current.Request.QueryString;
                        break;
                    default:
                        return false;
                }
                IDictionary<string, string> parameters = new Dictionary<string, string>();
                string sign = string.Empty;
                for (int i = 0; i < form.Count; i++)
                {
                    string key = form.Keys[i];
                    if (string.Equals(key,"sign",StringComparison.OrdinalIgnoreCase))
                    {
                         sign = form["sign"];
                        continue;
                    }
                    parameters.Add(key,form[key]);
                }
                return string.Equals(SignRequest(parameters, secret, false), sign,StringComparison.OrdinalIgnoreCase);
            }
    复制代码

    3、对用户信息进行签名(通用权限管理系统最新的安全校验方法) ,实现了链接只可以使用一次

    复制代码
            /// <summary>
            /// 对登录的用户进行数字签名
            /// </summary>
            /// <param name="userLogOnResult">登录信息</param>
            /// <returns>进行过数字签名的用户登录信息</returns>
            public static bool VerifySignature(BaseUserInfo userInfo)
            {
                bool result = false;
    
                if (userInfo != null && !string.IsNullOrEmpty(userInfo.Signature))
                {
                    if (string.IsNullOrEmpty(userInfo.Code))
                    {
                        userInfo.Code = string.Empty;
                    }
                    if (string.IsNullOrEmpty(userInfo.CompanyCode))
                    {
                        userInfo.CompanyCode = string.Empty;
                    }
                    if (string.IsNullOrEmpty(userInfo.CompanyId))
                    {
                        userInfo.CompanyId = string.Empty;
                    }
                    if (string.IsNullOrEmpty(userInfo.CompanyName))
                    {
                        userInfo.CompanyName = string.Empty;
                    }
                    if (string.IsNullOrEmpty(userInfo.DepartmentCode))
                    {
                        userInfo.DepartmentCode = string.Empty;
                    }
                    if (string.IsNullOrEmpty(userInfo.DepartmentId))
                    {
                        userInfo.DepartmentId = string.Empty;
                    }
                    if (string.IsNullOrEmpty(userInfo.DepartmentName))
                    {
                        userInfo.DepartmentName = string.Empty;
                    }
                    if (string.IsNullOrEmpty(userInfo.Id))
                    {
                        userInfo.Id = string.Empty;
                    }
                    if (string.IsNullOrEmpty(userInfo.NickName))
                    {
                        userInfo.NickName = string.Empty;
                    }
                    if (string.IsNullOrEmpty(userInfo.OpenId))
                    {
                        userInfo.OpenId = string.Empty;
                    }
                    if (string.IsNullOrEmpty(userInfo.RealName))
                    {
                        userInfo.RealName = string.Empty;
                    }
                    if (string.IsNullOrEmpty(userInfo.UserName))
                    {
                        userInfo.UserName = string.Empty;
                    }
                    // 需要签名的内容部分
                    string dataToSign = userInfo.Code + "_"
                        + userInfo.CompanyCode + "_"
                        + userInfo.CompanyId + "_"
                        + userInfo.CompanyName + "_"
                        + userInfo.DepartmentCode + "_"
                        + userInfo.DepartmentId + "_"
                        + userInfo.DepartmentName + "_"
                        + userInfo.Id + "_"
                        + userInfo.IdentityAuthentication.ToString() + "_"
                        + userInfo.IsAdministrator.ToString() + "_"
                        + userInfo.NickName + "_"
                        + userInfo.OpenId + "_"
                        + userInfo.RealName + "_"
                        + userInfo.UserName;
    
                    result = userInfo.Signature == DotNet.Utilities.SecretUtil.md5(dataToSign);
                }
    
                return result;
            }
    复制代码

    在用户登录成功以后要对返回的用户信息进行一次签名

    UserLogOnResult result = new UserLogOnResult();

    result = userManager.LogOnByNickName(userName, password, openId, createOpenId, systemCode, ipAddress, macAddress, computerName, checkUserPassword, validateUserOnly, checkMacAddress, sourceType, targetApplication, targetIp);

     result.UserInfo = ServiceUtil.CreateSignature(result.UserInfo);

    code的生成

    复制代码
            /// <summary>
            /// 获取登录操作的验证码
            /// code作为换取access_token的票据,每次用户授权带上的code将不一样,code只能使用一次,5分钟未被使用自动过期。 
            /// </summary>
            /// <param name="userInfo">用户信息</param>
            /// <returns>操作码</returns>
            public static BaseResult GetAuthorizationCode(BaseUserInfo userInfo)
            {
                BaseResult result = new BaseResult();
                
                if (ServiceUtil.VerifySignature(userInfo))
                {
                    // 产生一个授权码
                    string authorizationCode = Guid.NewGuid().ToString("N");
                    // 设置缓存服务器,消费一次,5分钟过期。
                    using (var redisClient = PooledRedisHelper.GetTokenClient())
                    {
                        // 2016-03-03 吉日嘎拉 让缓存早点儿失效
                        DateTime expiresAt = DateTime.Now.AddMinutes(5);
                        string key = "code:" + authorizationCode;
                        redisClient.Set(key, userInfo.OpenId, expiresAt);
                    }
                    result.ResultValue = authorizationCode;
                    result.Status = true;
                    result.StatusCode = Status.OK.ToString();
                    result.StatusMessage = Status.OK.ToDescription();
                    result.CreateSignature(userInfo);
                }
    
                return result;
            }
    复制代码

    code的验证

    复制代码
            /// <summary>
            /// 验证授权码
            /// 用掉一次后,一定要消费掉,确保只能用一次。
            /// </summary>
            /// <param name="userInfo">当前用户信息</param>
            /// <param name="code">授权码</param>
            /// <param name="openId">用户唯一识别码</param>
            /// <returns>验证成功</returns>
            public static bool VerifyAuthorizationCode(BaseUserInfo userInfo, string code, out string openId)
            {
                bool result = false;
                openId = string.Empty;
    
                if (userInfo != null && !ServiceUtil.VerifySignature(userInfo))
                {
                    return result;
                }
    
                using (var redisClient = PooledRedisHelper.GetTokenClient())
                {
                    // 2016-03-03 吉日嘎拉 让缓存早点儿失效
                    string key = "code:" + code;
                    openId = redisClient.Get<string>(key);
                    if (!string.IsNullOrEmpty(openId))
                    {
                        result = true;
                        if (userInfo != null && !string.IsNullOrEmpty(userInfo.OpenId))
                        {
                            result = userInfo.OpenId.Equals(openId);
                        }
                    }
                    redisClient.Remove(key);
                }
    
                return result;
            }
    复制代码

    返回数据结果类

    复制代码
        /// <summary>
        /// BaseResult  JsonResult<T>
        /// 
        /// 修改记录
        /// 
        ///        2016.05.12 版本:2.1 JiRiGaLa 增加 Signature 数字签名。
        ///        2016.01.07 版本:2.0 JiRiGaLa 增加 RecordCount。
        ///        2015.11.16 版本:1.1 SongBiao 增加JsonResult<T> 泛型 可以带数据返回。
        ///        2015.09.16 版本:1.1 JiRiGaLa Result 修改为 Status。
        ///        2015.09.15 版本:1.0 JiRiGaLa 添加返回标准定义。
        ///        
        /// <author>
        ///        <name>JiRiGaLa</name>
        ///        <date>2016.05.12</date>
        /// </author> 
        /// </summary>
        [Serializable]
        public class BaseResult
        {
            /// <summary>
            /// 操作是否成功
            /// 2015-09-16 吉日嘎拉 按宋彪建议进行修正
            /// </summary>
            public bool Status = false;
    
            /// <summary>
            /// 返回值
            /// </summary>
            public string ResultValue = "";
    
            /// <summary>
            /// 返回状态代码
            /// </summary>
            public string StatusCode = "UnknownError";
    
            /// <summary>
            /// 返回消息内容
            /// </summary>
            public string StatusMessage = "未知错误";
    
            /// <summary>
            /// 查询分页数据时返回记录条数用
            /// </summary>
            public int RecordCount = 0;
    
            /// <summary>
            /// 数字签名(防止篡改)
            /// </summary>
            public string Signature = string.Empty;
    
            /// <summary>
            /// 对登录的用户进行数字签名
            /// </summary>
            /// <param name="userInfo">登录信息</param>
            /// <returns>进行过数字签名的用户登录信息</returns>
            public string CreateSignature(BaseUserInfo userInfo)
            {
                if (userInfo != null)
                {
                    if (!string.IsNullOrEmpty(userInfo.Signature))
                    {
                        // 需要签名的内容部分
                        string dataToSign = userInfo.Signature + "_"
                            + ResultValue + "_"
                            + Status.ToString() + "_"
                            + StatusCode.ToString() + "_"
                            + BaseSystemInfo.SecurityKey + "_";
                        // 进行签名
                        Signature = DotNet.Utilities.SecretUtil.md5(dataToSign);
                    }
                }
    
                return Signature;
            }
    
            /// <summary>
            /// 对登录的用户进行数字签名
            /// </summary>
            /// <param name="userInfo">登录信息</param>
            /// <returns>进行过数字签名的用户登录信息</returns>
            public bool VerifySignature(BaseUserInfo userInfo)
            {
                bool result = false;
    
                if (userInfo != null)
                {
                    if (!string.IsNullOrEmpty(userInfo.Signature))
                    {
                        // 需要签名的内容部分
                        string dataToSign = userInfo.Signature + "_"
                            + ResultValue + "_"
                            + Status.ToString() + "_"
                            + StatusCode.ToString() + "_"
                            + BaseSystemInfo.SecurityKey + "_";
                        // 进行签名
                        result = Signature == DotNet.Utilities.SecretUtil.md5(dataToSign);
                    }
                }
    
                return result;
            }
        }
    
        /// <summary>
        /// Json格式带返回数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        [Serializable]
        public class JsonResult<T> : BaseResult
        {
            public T Data { get; set; }
        }

      觉得可以,帮忙顶一下,谢谢。
      
        
    
    
    
    明明可以靠才华吃饭,非要靠脸~
  • 相关阅读:
    管理员技术(三): 配置静态网络地址、 使用yum软件源 、 升级Linux内核、查找并处理文件、查找并提取文件内容
    管理员技术(二): 访问练习用虚拟机、 命令行基础技巧 、 挂载并访问光盘设备、ls列表及文档创建、复制删除移动
    管理员技术(一):装机预备技能、安装一台RHEL7虚拟机、使用RHEL7图形桌面、Linux命令行基本操作
    基础(三):yum(RedHat系列)和apt-get(Debian系列 )用法及区别
    基础(二):Linux系统/etc/init.d目录和/etc/rc.local脚本
    基础(一):SCSI硬盘与IDE硬盘有什么区别
    高级运维(六):源码安装Redis缓存服务、常用Redis数据库操作指令、配置Redis主从服务器
    错题
    count 【mysql】
    自连接和子查询
  • 原文地址:https://www.cnblogs.com/lycsmzl/p/5684514.html
Copyright © 2011-2022 走看看