webApi簽名驗證


還是一如既往先上結構圖如下:

上一講說明了redis,也謝謝心態的建議。這里經過改進后的redis的地址

當然這里是加密了的,具體實現如下圖:

這里提供的解密。

先把加密解密的幫助類放上來。

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace KuRuMi.Mio.DoMain.Infrastructure.Common
{
    /// <summary>
    /// 對稱加密幫助類
    /// </summary>
    public class CryptographyExtension
    {
        // 對稱加密算法提供器
        private ICryptoTransform encryptor;     // 加密器對象
        private ICryptoTransform decryptor;     // 解密器對象
        private const int BufferSize = 1024;
        private static string dataKey = "XXXXXXXX";

        public CryptographyExtension(string algorithmName, string key)
        {
            SymmetricAlgorithm provider = SymmetricAlgorithm.Create(algorithmName);
            provider.Key = Encoding.UTF8.GetBytes(key);
            provider.IV = new byte[] { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF };

            encryptor = provider.CreateEncryptor();
            decryptor = provider.CreateDecryptor();
        }

        public CryptographyExtension(string key) : this("TripleDES", key) { }

        /// <summary>
        /// 加密算法
        /// </summary>
        /// <param name="clearText"></param>
        /// <returns></returns>
        public string Encrypt(string clearText)
        {
            // 創建明文流
            byte[] clearBuffer = Encoding.UTF8.GetBytes(clearText);
            MemoryStream clearStream = new MemoryStream(clearBuffer);

            // 創建空的密文流
            MemoryStream encryptedStream = new MemoryStream();

            CryptoStream cryptoStream =
                new CryptoStream(encryptedStream, encryptor, CryptoStreamMode.Write);

            // 將明文流寫入到buffer中
            // 將buffer中的數據寫入到cryptoStream中
            int bytesRead = 0;
            byte[] buffer = new byte[BufferSize];
            do
            {
                bytesRead = clearStream.Read(buffer, 0, BufferSize);
                cryptoStream.Write(buffer, 0, bytesRead);
            } while (bytesRead > 0);

            cryptoStream.FlushFinalBlock();

            // 獲取加密后的文本
            buffer = encryptedStream.ToArray();
            string encryptedText = Convert.ToBase64String(buffer);
            return encryptedText;
        }

        /// <summary>
        /// 解密算法
        /// </summary>
        /// <param name="encryptedText"></param>
        /// <returns></returns>
        public string Decrypt(string encryptedText)
        {
            byte[] encryptedBuffer = Convert.FromBase64String(encryptedText);
            Stream encryptedStream = new MemoryStream(encryptedBuffer);

            MemoryStream clearStream = new MemoryStream();
            CryptoStream cryptoStream =
                new CryptoStream(encryptedStream, decryptor, CryptoStreamMode.Read);

            int bytesRead = 0;
            byte[] buffer = new byte[BufferSize];

            do
            {
                bytesRead = cryptoStream.Read(buffer, 0, BufferSize);
                clearStream.Write(buffer, 0, bytesRead);
            } while (bytesRead > 0);

            buffer = clearStream.GetBuffer();
            string clearText =
                Encoding.UTF8.GetString(buffer, 0, (int)clearStream.Length);

            return clearText;
        }

        /// <summary>
        /// 加密
        /// </summary>
        /// <param name="clearText"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static string Encrypts(string clearText)
        {
            CryptographyExtension helper = new CryptographyExtension(dataKey);
            return helper.Encrypt(clearText);
        }

        /// <summary>
        /// 解密
        /// </summary>
        /// <param name="encryptedText"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static string Decrypts(string encryptedText)
        {
            CryptographyExtension helper = new CryptographyExtension(dataKey);
            return helper.Decrypt(encryptedText);
        }
    }
}

完成這一些后,下面來看看簽名驗證。本來是寫好了token+簽名的驗證,因為token目前還有些問題后來刪掉了,改用簽名驗證。

這個方法是放在client端返回加密后的key。因為博主的項目全是post請求,這里就沒有補充get請求。

 public static T Post<T>(string url, string data, string appid)
        {
            byte[] bytes = Encoding.UTF8.GetBytes(data);
            HttpWebRequest request = WebRequest.CreateHttp(url) as HttpWebRequest;
            //加入到頭信息中
            request.Headers.Add("appid", appid);//當前的用戶的請求id
            request.Headers.Add("sign", GetSignature());//簽名驗證

            //寫數據
            request.Method = "POST";
            request.ContentLength = bytes.Length;
            request.ContentType = "application/json";
            Stream reqstream = request.GetRequestStream();
            reqstream.Write(bytes, 0, bytes.Length);

            //讀數據
            request.Timeout = 30000;
            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);
        }

然后是調用:

頁面上的寫法就是在ajax里面加入請求頭

 

        $(function () {
            $("#regist").click(function () {
                var data = { userName: $("#text_r").val(), email: $("#email_r").val(), passWord: $("#password_r").val() };
                debugger;
                $.ajax({
                    //"Content-Type":"application/ json" //這里如果將此放入到headers里面會出現傳入DTO參數的時候為空
                    headers: { appid: "2xl7w0Doqog=", sign: "MwOMp5bATVf1N2qNmAxW1GL1mduieOjsLHe45frBuISIpRE9OWncZ569sZraRQnwmWuQHNmJZJjCT/FaWsSiZw=="},
                    type: 'post',
                    datatype: 'json',
                    data: data,
                    url: 'http://localhost:13292/Api/App/DataForAjax',
                    success: function (data) {
                        $('small').html(data);
                        $('small').delay(3000).hide(0);
                    }
                });
            });
  //"Content-Type":"application/ json" //這里如果將此放入到headers里面會出現傳入DTO參數的時候為空

這里就是加上了
Content-Type":"application/ json造成的
去掉了之后

下面是filter代碼

using KuRuMi.Mio.AppService.Common;
using KuRuMi.Mio.AppService.Models;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;

namespace KuRuMi.Mio.AppService.Filter
{
    public class SignSecretFilter : ActionFilterAttribute
    {
        public override void OnActionExecuting(HttpActionContext actionContext)
        {
            ResultMsg resultMsg = null;
            string appId = string.Empty;
            string sign = string.Empty;
            if (actionContext.Request.Headers.Contains("appid"))
            {
                appId = HttpUtility.UrlDecode(actionContext.Request.Headers.GetValues("appid").FirstOrDefault());
            }
            if (actionContext.Request.Headers.Contains("sign"))
            {
                sign = HttpUtility.UrlDecode(actionContext.Request.Headers.GetValues("sign").FirstOrDefault());
            }

            //判斷請求頭是否包含以下參數
            if (string.IsNullOrEmpty(appId) || string.IsNullOrEmpty(sign))
            {
                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;
            }
            //驗證簽名算法
            bool result = SignExtension.Validate(appId, sign);
            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;
            }
        }
    }
}

服務器端驗證簽名的方法:

using KuRuMi.Mio.DoMain.Infrastructure.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Web;

namespace KuRuMi.Mio.AppService.Common
{
    /// <summary>
    /// 判斷簽名算法
    /// </summary>
    public class SignExtension
    {
        private static readonly string keys = "Kurumi";
        /// <summary>
        /// 判斷簽名算法
        /// </summary>
        /// <param name="appId"></param>
        /// <param name="url"></param>
        /// <param name="sign">簽名</param>
        /// <returns></returns>
        public static bool Validate(string appId, string sign)
        {
            byte[] bytes = Encoding.UTF8.GetBytes(ConfigManagerExtension.SecretKey);
            string signs = string.Empty;
            if (appId != "1000")
                signs = CryptographyExtension.Decrypts(appId) + keys;
            else
                signs = appId + keys;
            byte[] val = Encoding.UTF8.GetBytes(string.Concat(signs.OrderBy(c => c)));//排序
            string key = null;
            using (HMACSHA512 SecretKey = new HMACSHA512(bytes))
            {
                var SecretKeyBytes = SecretKey.ComputeHash(val);
                key = Convert.ToBase64String(SecretKeyBytes);
            }
            return (sign.Equals(key, StringComparison.Ordinal));
        }
    }
}

 


免責聲明!

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



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