zoukankan      html  css  js  c++  java
  • ASP.NET Core WebApi使用ActionFilterAttribute过滤器

    为保护接口安全性,过滤非法请求来源,本篇博客介绍如何在 ASP.NET Core WebApi 中使用 ActionFilterAttribute 过滤器过滤非法请求。

    基本思路:前端在请求头中加入加密后的 Token 和 TimeSpan 两个字段,Token前后端保持一致,加密方法、密钥、向量前后端保持一致,后端在接收到加密的两个字段后解密进行验证,如果来源合法,则返回接口数据,否则给出警告提示。

    一、配置 appsettings.json 文件

    "BaseInfo": {
      "WeXinToken": "dieidkdlalsd",
      "AesKey": "j67aso1dfle3ja45",
      "AesIv": "2jas5odf7lej6aop"
    }
    

    二、新建 MyApiFilter 类,重写 OnActionExecuting 方法,过滤非法来源

    public class MyApiFilter : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext context)
        {
            try
            {
                //获取请求头中的Token和TimeSpan
                var token = context.HttpContext.Request.Headers["Token"].ToString();
                var timespan = context.HttpContext.Request.Headers["TimeSpan"].ToString();
                //验证timespan和token
                if (CheckFromIsRight(timespan, token))
                {
                    base.OnActionExecuting(context);
                }
                else
                {
                    context.Result = new JsonResult("请求来源非法");
                }
            }
            catch (Exception)
            {
                context.Result = new JsonResult("请求来源非法");
            }
        }
        public static bool CheckFromIsRight(string timespan, string token)
        {
            bool result = false;
            if (!string.IsNullOrEmpty(timespan) && !string.IsNullOrEmpty(token))
            {
                try
                {
                    //时间差小于两分钟
                    if (ConvertToTimeFromSpan(MySecret.AesDecrypt(timespan)).Subtract(DateTime.Now).Minutes <= 2)
                    {
                        //读取配置文件中的token
                        string weixinToken = new ConfigurationBuilder()
                            .SetBasePath(Directory.GetCurrentDirectory())
                            .AddJsonFile("appsettings.json", true, true)
                            .Build().GetSection("BaseInfo:WeXinToken").Value;
                        if (MySecret.AesDecrypt(token).Equals(weixinToken))
                        {
                            return true;
                        }
                    }
                }
                catch (Exception)
                {
    
                    throw;
                }
            }
            return result;
        }
    
        //将时间戳转换成正常时间
        public static DateTime ConvertToTimeFromSpan(string timespan)
        {
            //开始时间 TimeZoneInfo.ConvertTimeFromUtc将协调世界时(UTC)转换为本地时区中的时间
            DateTime start = TimeZoneInfo.ConvertTimeFromUtc(new DateTime(1970, 1, 1), TimeZoneInfo.Local);
            //13位需要加上4个0
            TimeSpan ts = new TimeSpan(long.Parse(timespan + "0000"));
            return start.Add(ts);
        }
    }
    

    三、新建 MySecret 类,用于加密解密

    public class MySecret
    {
        //密钥与向量,与前端保持一致
        private static readonly string aeskey = "j67aso1dfle3ja45";
        private static readonly string aesiv = "2jas5odf7lej6aop";
    
        /// <summary>
        ///  AES 加密 
        /// </summary>
        /// <param name="str">明文(待加密)</param>
        /// <returns></returns>
        public static string AesEncrypt(string str)
        {
            if (string.IsNullOrEmpty(str))
            {
                return "";
            }
            Byte[] toEncryptArray = Encoding.UTF8.GetBytes(str);
    
            RijndaelManaged rm = new RijndaelManaged
            {
                Key = Encoding.UTF8.GetBytes(aeskey),
                Mode = CipherMode.CBC,
                Padding = PaddingMode.PKCS7,
                IV = Encoding.UTF8.GetBytes(aesiv),
            };
    
            ICryptoTransform cTransform = rm.CreateEncryptor();
            Byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
    
            return Convert.ToBase64String(resultArray, 0, resultArray.Length);
        }
    
        /// <summary>
        ///  AES 解密
        /// </summary>
        /// <param name="str">明文(待解密)</param>
        /// <returns></returns>
        public static string AesDecrypt(string str)
        {
            if (string.IsNullOrEmpty(str))
            {
                return "";
            }
    
            try
            {
                Byte[] toEncryptArray = Convert.FromBase64String(str);
    
                RijndaelManaged rm = new RijndaelManaged
                {
                    Key = Encoding.UTF8.GetBytes(aeskey),
                    Mode = CipherMode.CBC,
                    Padding = PaddingMode.PKCS7,
                    IV = Encoding.UTF8.GetBytes(aesiv),
                };
    
                ICryptoTransform cTransform = rm.CreateDecryptor();
                Byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
    
                return Encoding.UTF8.GetString(resultArray);
            }
            catch (Exception)
            {
                return str;
            }
        }
    }
    

    tips:为提高安全性,密钥与向量应配置在appsetting.json文件中再封装方法获取,本篇博客为简化代码未配置。

            微信小程序crypto.js AES加解密:https://www.cnblogs.com/gygg/p/12793227.html

    四、使用过滤器

    在需要过滤的 Controller 中加入【MyApiFilter】特性

    在请求头中加入timespan和token字段

    请求来源合法,返回接口数据

    否则返回警告提示

    End!

  • 相关阅读:
    Java类型转换
    Java数据类型
    Java运行机制-简单理解
    Dos基础命令
    MarkDown
    MSP430 ADC12模块(转)
    解决拷贝中文注释到KEIL4.6中呈现乱码的问题
    ADS1.2 DEBUG调试时提示:erro starting external process,Process error code 87(0x57)
    MDK4.6提示不能找到库
    在JLINK4.12的安装目录下没有LPC2214.jflash文件的解决办法
  • 原文地址:https://www.cnblogs.com/gygg/p/13279688.html
Copyright © 2011-2022 走看看