授权过滤器—MVC中使用授权过滤器实现JWT权限认证

授权,过滤器,mvc,使用,实现,jwt,权限,认证 · 浏览次数 : 166

小编点评

**代码摘要** 该代码包含生成和验证 JWT 的授权过滤器测试代码。代码主要包含以下部分: * **`JwtController`** 类:负责创建和获取 JWT token。 * **``AuthFilterTestController`** 类:负责测试授权过滤器。 * **``MyAuthorizeFilter`** 和 **``MyAuthorizeFilterAttribute`** 类:用于定义授权过滤器特性。 * **```JwtHelper`** 类:用于生成和验证 JWT token。 **主要功能** * 生成和获取 JWT token。 * 测试授权过滤器是否能正确授权用户。 * 使用后缀属性(`MyAuthorizeFilterAttribute`)定义授权过滤器特性。 **主要测试用例** * ``AuthTest`` 测试授权过滤器是否能正确授权用户。 * ``JwtHelper`` 类中的 ``SetJwtEncode`` 方法用于生成 JWT token。 * ``JwtHelper`` 类中的 ``GetJwtDecode`` 方法用于解析 JWT token。 **测试结果** 测试结果显示,授权过滤器测试代码能正确执行授权操作。

正文

一、什么是过滤器?

过滤器定义:

​ 过滤器与中间件很相似,过滤器(Filters)可在管道(pipeline)特定阶段(particular stage)前或后执行操作,可以将过滤器视为拦截器(interceptors)。在.NET MVC开发中,权限验证是非常重要的一部分。通过使用授权过滤器可以很方便地实现权限验证功能。这篇主要分享授权过滤器的使用。

二、过滤器的种类:

​ 过滤器总共有五种,Authorization Filter(授权过滤器),Resource Filter(资源过滤器),Action Filter(操作过滤器),Exception Filter(异常过滤器),Result Filter(结果过滤器)。它们在管道里有先后的执行顺序,最先执行的是授权过滤器。

图片

授权过滤器:

最先执行,用于判断用户是否授权。如果未授权,则直接结束当前请求。这种类型的过滤器实现了 IAsyncAuthorizationFilterIAuthorizationFilter 接口。

资源过滤器:

在Authorization过滤器后执行,并在执行其他过滤器 (除Authorization过滤器外)之前和之后执行。由于它在Action之前执行,因而可以用来对请求判断,根据条件来决定是否继续执行Action。这种类型过滤器实现了 IAsyncResourceFilterIResourceFilter 接口。

操作过滤器:

在Action执行的前后执行。与Resource过滤器不一样,它在模型绑定后执行。这种类型的过滤器实现了 IAsyncActionFilterIActionFilter 接口。

异常过滤器:

异常过滤器用于管理未处理的异常,比如:用于捕获异常。这种类型的过滤器实现了 IAsyncExceptionFilterIExceptionFilter 接口。

结果过滤器:

在 IActionResult 执行的前后执行,使用它能够控制Action的执行结果,比如:格式化结果等。需要注意的是,它只有在Action方法成功执行完成后才会运行。这种类型过滤器实现了 IAsyncResultFilterIResultFilter 接口。

图片

三、过滤器的级别范围:

​ 过滤器的级别总共有三种,分别是全局级别过滤器(Global scope)、控制器级别过滤器(Controller scope)和动作级别过滤器(Action scope)。

全局级别过滤器:

​ 这意味着过滤器覆盖了整个MVC管道。对特定MVC路由的每次调用都将通过该过滤器。在Startup类的ConfigureServices方法中把过滤器添加到全局过滤器集合。

代码实现:

services.AddMvc(options =>
{
//全局级别过滤器:添加到全局过滤器集合
options.Filters.Add<MyAuthorizeFilterAttribute>();//此处必须过滤器名称全部书写,不能省略后缀Attribute,还有就是使用全局过滤器可以不继承特性Attribute
});

控制器级别过滤器:

​ 在这种情况下,过滤器被初始化为一个或多个控制器类中的属性。它将仅对已定向到目标控制器的请求采取行动。定义时需要继承抽象类Attribute,使用时需要的Controller上打上特性标签。

代码实现:

/// <summary>
    /// 授权过滤器测试
    /// </summary>
    public class AuthFilterTestController : ControllerBase
    {
      
        /// <summary>
        /// 授权过滤器测试
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        [Route("Test")]
        public ActionResult AuthTest()
        {
            return Ok(new { IsSucesss =true, Msg="授权过滤器测试成功" });  
        }
    }

动作级别过滤器:

​ 筛选器在一个或多个操作方法中初始化为属性。它将仅对已定向到目标方法的请求执行操作。定义时需要继承抽象类Attribute,使用时需要的Action上打上特性标签

代码实现:

 /// <summary>
    /// 授权过滤器测试
    /// </summary>
    //[MyAuthorizeFilterAttribute]//控制器级别过滤器
    [MyAuthorizeFilter]  //备注:特性后缀Attribute也可以省略
    [Route("api/Auth")]
    public class AuthFilterTestController : ControllerBase
    {
      
        /// <summary>
        /// 授权过滤器测试
        /// </summary>
        /// <returns></returns>
        //[MyAuthorizeFilterAttribute]//动作级别过滤器
        [MyAuthorizeFilter]  //备注:特性后缀Attribute也可以省略
        [HttpPost]
        [Route("Test")]
        public ActionResult AuthTest()
        {
            return Ok(new { IsSucesss =true, Msg="授权过滤器测试成功" });  
        }
    }

四、定义授权过滤器:

创建JwtHelper帮助类:

​ 安装NuGet包JWT,用于生成token和进行token验证。

图片

 /// <summary>
    /// JWT帮助类
    /// </summary>
    public class JwtHelper
    {
        //私钥appsettings.json中配置
        private static string secret = Helper.ConfigHelper.GetSectionValue("TokenSecret");

        /// <summary>
        /// 生成JwtToken
        /// </summary>
        /// <param name="payload">不敏感的用户数据</param>
        /// <returns></returns>
        public static string SetJwtEncode(Dictionary<string, object> payload)
        {
            IJwtAlgorithm algorithm = new HMACSHA256Algorithm();
            IJsonSerializer serializer = new JsonNetSerializer();
            IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
            IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder);

            var token = encoder.Encode(payload, secret);
            return token;
        }

        /// <summary>
        /// 根据jwtToken获取实体
        /// </summary>
        /// <param name="token">jwtToken</param>
        /// <returns></returns>
        public static LoginUserInfo GetJwtDecode(string token)
        {
            LoginUserInfo loginUserInfo = new LoginUserInfo();
            try
            {
               
                IJsonSerializer serializer = new JsonNetSerializer();
                IDateTimeProvider provider = new UtcDateTimeProvider();
                IJwtValidator validator = new JwtValidator(serializer, provider);
                IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
                var algorithm = new HMACSHA256Algorithm();
                IJwtDecoder decoder = new JwtDecoder(serializer, validator, urlEncoder, algorithm);
                loginUserInfo = decoder.DecodeToObject<LoginUserInfo>(token, secret, verify: true);//token为之前生成的字符串
                return loginUserInfo;
            }
            catch (System.Exception ex)
            {
                return loginUserInfo;
            }
           
        }

        /// <summary>
        /// 登录人员信息
        /// </summary>
        public class LoginUserInfo
        {
            /// <summary>
            /// 用户名
            /// </summary>
            public string username { get; set; }
            /// <summary>
            /// 密码
            /// </summary>
            public string pwd { get; set; }
            /// <summary>
            /// Token 过期时间
            /// </summary>
            public double exp { get; set; }
        }

        /// <summary>
        ///获取返回Token信息
        /// </summary>
        public class TokenResult
        {
            /// <summary>
            /// 是否成功
            /// </summary>
            public bool success { get; set; }
            /// <summary>
            /// Token字符串
            /// </summary>
            public string token { get; set; }
            /// <summary>
            /// 提示信息
            /// </summary>
            public string message { get; set; }
        }
    }

创建ConfigHelper帮助类:

读取加密key值,用于进行生成token时加密和验证token时校验。

 /// <summary>
    /// 配置文件帮助类
    /// </summary>
    public static class ConfigHelper
    {
        private static IConfiguration _configuration;

        static ConfigHelper()
        {
            //在当前目录或者根目录中寻找appsettings.json文件
            var fileName = "appsettings.json";

            var directory = AppContext.BaseDirectory;
            directory = directory.Replace("\\", "/");

            var filePath = $"{directory}/{fileName}";
            if (!File.Exists(filePath))
            {
                var length = directory.IndexOf("/bin");
                filePath = $"{directory.Substring(0, length)}/{fileName}";
            }

            var builder = new ConfigurationBuilder()
                .AddJsonFile(filePath, false, true);

            _configuration = builder.Build();
        }

        public static string GetSectionValue(string key)
        {
            return _configuration.GetSection(key).Value;
        }

        /// <summary>
        /// 解析数据库字符串
        /// </summary>
        /// <param name="parameter"></param>
        /// <param name="providerName"></param>
        /// <returns></returns>
        public static string GetParameterValue(string parameter, string connectionString)
        {
            var vars = connectionString.Split(';');
            for (var i = 0; i < vars.Length; i++)
            {
                var pair = vars[i].Split('=');
                if (pair[0] == parameter) { return pair[1]; }
            }
            return "";
        }
    }

appsettings.json添加配置节点:

​ 配置文件中,根节点添加节点TokenSecret。

{
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "AllowedHosts": "*",
  "TokenSecret": "GQDstcKsx0NHjPOuXOYg5MbeJ1XT0uFiwDVvVBrk"//添加加密key值
}

定义Filter:

​ 继承类Attribute, 接口IAuthorizationFilter ,然后实现接口OnAuthorization方法,书写自定义业务逻辑。

  /// <summary>
    /// 授权过滤器
    /// </summary>
    public class MyAuthorizeFilterAttribute : Attribute, IAuthorizationFilter 
    {

   
        #region IAuthorizationFilter 授权过滤器 

        /// <summary>
        /// 授权过滤器实现方法
        /// </summary>
        /// <param name="context"></param>
        public void OnAuthorization(AuthorizationFilterContext context)
        {
            var authHeader = context.HttpContext.Request.Headers["Authorization"];
            if (string.IsNullOrWhiteSpace(authHeader))
            {
                //var json =  JsonConvert.SerializeObject(new OperationResult(OperationResultType.Error, "保存失败"));
                //此接口必须携带token访问!
                context.Result = new ContentResult()
                {

                    Content = "此接口必须携带token访问,请登录携带Token访问",
                    ContentType = "text/html"//application/json
                };
            }
            else //字段值不为空
            {
                authHeader = authHeader.ToString().Replace("Bearer", "").Trim();//去掉Bearer字串
                if (authHeader == "")
                {
                    context.Result = new ContentResult()
                    {
                        Content = "token验证失败:您没有权限调用此接口,请登录重新获取Token",
                        ContentType = "text/html"
                    };
                }
                else
                {
                    LoginUserInfo LoginInfo = JwtHelper.GetJwtDecode(authHeader);
                    string UserName = LoginInfo.username;
                    string PassWord = LoginInfo.pwd;
                    double ExpireTimeStamp = LoginInfo.exp;
                    if (isTokenExpire(ExpireTimeStamp)) //这里应该验证有效期
                    {
                        //token验证失败:您没有权限调用此接口,请登录获取Token
                        context.Result = new ContentResult()
                        {
                            Content = "token验证失败:您没有权限调用此接口,请登录重新获取Token",
                            ContentType = "text/html"
                        };
                    }
                }

            }
        }
        #endregion

        /// <summary>
        /// 时间戳字符串
        /// </summary>
        /// <param name="timestamp"></param>
        /// <returns></returns>
        private bool isTokenExpire(double timestamp)
        {
            try
            {
                System.DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1));//当地时区
                var expireTime = startTime.AddSeconds(timestamp);
                if (expireTime > DateTime.Now)
                {
                    return false;//未过期
                }
                else
                {
                    return true;//已过期
                }
            }
            catch (Exception ex)
            {
                return true;
            }
        }

    }

五、定义接口:

获取token接口:

 /// <summary>
    /// JWT 
    /// </summary>
    [Route("api/Jwt")]
    public class JwtController : ControllerBase
    {

        /// <summary>
        /// 创建JwtToken
        /// </summary>
        /// <param name="username"></param>
        /// <param name="pwd"></param>
        /// <returns></returns>
        [HttpGet]
        [AllowAnonymous]
        [Route("getToken")]
        public ActionResult CreateToken(string username, string pwd)
        {
            TokenResult result = new TokenResult();
            result.token = "";
            result.success = false;

            if (username != "" && pwd != "")
            {
                IDateTimeProvider provider = new UtcDateTimeProvider();
                var now = provider.GetNow();
                var unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
                var secondsSinceEpoch = Math.Round((now - unixEpoch).TotalSeconds);
                var payload = new Dictionary<string, object>
                {
                    { "username",username },
                    { "pwd", pwd },
                    { "exp", secondsSinceEpoch + 60*30} //失效时间秒  此处设置30分钟
                };

                result.token = SetJwtEncode(payload);
                result.success = true;
                result.message = "生成token成功";
            }
            else
            {
                result.message = "生成token失败";
            }

            return Ok(result);
        }

    }

http测试访问接口:

 /// <summary>
    /// 授权过滤器测试
    /// </summary>
    //[MyAuthorizeFilterAttribute]//控制器级别过滤器
    //[MyAuthorizeFilter]  //备注:特性后缀Attribute也可以省略
    [Route("api/Auth")]
    public class AuthFilterTestController : ControllerBase
    {
      
        /// <summary>
        /// 授权过滤器测试
        /// </summary>
        /// <returns></returns>
        //[MyAuthorizeFilterAttribute]//动作级别过滤器
        [MyAuthorizeFilter]  //备注:特性后缀Attribute也可以省略
        [HttpPost]
        [Route("Test")]
        public ActionResult AuthTest()
        {
            return Ok(new { IsSucesss =true, Msg="授权过滤器测试成功" });  
        }
    }

六、验证:

​ 根据上面测试接口的特性标签位置,此处进行验证使用动作级别过滤器进行验证,只对这一个接口进行授权校验。

未授权访问:

不携带Token访问:

图片

授权访问:

获取Token:

图片

携带Token访问

图片

与授权过滤器—MVC中使用授权过滤器实现JWT权限认证相似的内容:

授权过滤器—MVC中使用授权过滤器实现JWT权限认证

## 一、什么是过滤器? ### 过滤器定义: ​ 过滤器与中间件很相似,**过滤器(Filters)**可在**管道(pipeline)**特定阶段(particular stage)前或后执行操作,可以将过滤器视为**拦截器(interceptors)**。在.NET MVC开发中,权限验证是非

操作过滤器—MVC中使用操作过滤器实现JWT权限认证

## 前言 上一篇文章分享了授权过滤器实现JWT进行鉴权,文章链接:[授权过滤器—MVC中使用授权过滤器实现JWT权限认证](https://www.cnblogs.com/wml-it/p/17612434.html),接下来将用操作过滤器实现昨天的JWT鉴权。 ## 一、什么是操作过滤器? ​

资源过滤器—MVC中使用资源过滤器实现不执行Action方法体读取缓存信息返回

## 前言 上两篇文章分享了过滤器实现JWT进行鉴权,分别是通过授权过滤器和操作过滤器实现,这两个过滤器也是最常用的。文章链接:[授权过滤器—MVC中使用授权过滤器实现JWT权限认证](https://www.cnblogs.com/wml-it/p/17612434.html),[操作过滤器—MV

SpringBoot实战:Spring Boot接入Security权限认证服务

引言 Spring Security 是一个功能强大且高度可定制的身份验证和访问控制的框架,提供了完善的认证机制和方法级的授权功能,是一个非常优秀的权限管理框架。其核心是一组过滤器链,不同的功能经由不同的过滤器。本文将通过一个案例将 Spring Security 整合到 SpringBoot中,要

造轮子之自定义授权策略

前面我们已经弄好了用户角色这块内容,接下来就是我们的授权策略。在asp.net core中提供了自定义的授权策略方案,我们可以按照需求自定义我们的权限过滤。这里我的想法是,不需要在每个Controller或者Action打上AuthorizeAttribute,自动根据ControllerName和

SQL 注入漏洞详解 - Union 注入

1)漏洞简介 SQL 注入简介 SQL 注入 即是指 Web 应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在 Web 应用程序中事先定义好的查询语句的结尾上添加额外的 SQL 语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应

PHP转Go系列 | ThinkPHP与Gin框架之OpenApi授权设计实践

工作中只要接触过第三方开放平台的都离不开 OpenApi,几乎各大平台都会有自己的 OpenApi 比如微信、淘宝、京东、抖音等。在 OpenApi 对接的过程中最首要的环节就是授权,获取到平台的授权 Token 至关重要。

【ASP.NET Core】按用户等级授权

验证和授权是两个独立但又存在联系的过程。验证是检查访问者的合法性,授权是校验访问者有没有权限查看资源。它们之间的联系——先验证再授权。 贯穿这两过程的是叫 Claim 的东东,可以叫它“声明”。没什么神秘的,就是由两个字符串组成的对象,一曰 type,一曰 value。type 和 value 有着

Kubernetes(K8S) 集群安全机制

概述 访问K8S集群,需要经过三个步骤完成具体操作 认证 鉴权(授权) 准入控制 进行访问时,过程中需要经过 ApiServer,做统一协调,比如门卫,访问过程中需要证书、token、或者用户名+密码,如果访问pod需要 ServiceAccount 认证 传输安全:对外不暴露8080端口,只能内部

详解Web应用安全系列(6)安全配置错误

Web攻击中的安全配置错误漏洞是一个重要的安全问题,它涉及到对应用程序、框架、应用程序服务器、Web服务器、数据库服务器等组件的安全配置不当。这类漏洞往往由于配置过程中的疏忽或错误,使得攻击者能够未经授权地访问系统数据或执行系统功能。 安全配置错误类漏洞是指在对Web应用及相关组件进行安全配置时,由