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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM