• 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));
            }
        }
    }
  • 相关阅读:
    【36氪收录】观「招商银行」隐私计算布局的思考
    如何用cmake编译
    docker | Ubuntu16.04安装与卸载docker
    通过删除注册表重新获得软件试用期
    k8s | 重启Kubernetes Pod的几种方式
    2021年终总结(一)
    凡是过往、皆为序章20210917PPT分享
    多厂商容器平台开发系统性总结
    VS2022安装.NetFramework4.0目标包的方法
    C# Winform窗体继承过程中,TableLayoutPanel是不支持继承的
  • 原文地址:https://www.cnblogs.com/edna-lzh/p/6952698.html
Copyright © 2020-2023  润新知