C#/.NET 日常开发技巧JWT+ActionFilter 简便控制器代码

Posted dotNET跨平台

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C#/.NET 日常开发技巧JWT+ActionFilter 简便控制器代码相关的知识,希望对你有一定的参考价值。

微信公众号:趣编程ACE
关注可了解更多.NET日常开发技巧,如需源码,请公众号留言 源码;

JWT+ActionFilter 简便控制器代码

这是微软关于过滤器的介绍:https://docs.microsoft.com/zh-cn/aspnet/core/mvc/controllers/filters?view=aspnetcore-6.0

今天的日常开发技巧是介绍下如何通过Authorization 和 Action Filter 来自动将登录用户的ID添加到控制器中去,这样就可以简化我们代码量了。

首先我们新建一个ApiController类继承ControllerBase  

1    [ApiController]
2    [Route("api/[controller]")]
3    [Authorize]   // 开启授权 登录成功后才能访问
4    [ActionFilter] // 自定义的一个属性 核心功能下文实现 用来实现自动将登录用户的ID添加到控制器中去
5    public abstract class ApiController:ControllerBase
6    
7        public string UserId  get; set; 
8    

上述代码我们创建一个抽象的基类控制器,这样就可以将[ActionFilter]应用到所有继承ApiController这个基类的控制器上,这样我们就可以规避很多重复的代码,与此同时我们定义一个UserId属性,便于每个派生类访问。

[Authorize]用来判断是否有权限调用控制器或者动作方法,常见的身份认证方案有JWT,下文代码也是基于此。
下面我们实现ActionFilter 属性

1public class ActionFilter : Attribute, IActionFilter
 2    
 3        // 动作方法执行结束调用
 4        public void OnActionExecuted(ActionExecutedContext context)
 5        
 6            // throw new NotImplementedException();
 7        
 8        // 动作方法执行前执行
 9        public void OnActionExecuting(ActionExecutingContext context)
10        
11            // throw new NotImplementedException();
12            var c = context.Controller as ApiController;
13            c.UserId = c.User.FindFirstValue(ClaimTypes.NameIdentifier);
14        
15    

在这个类中,我们继承了Attribute ,这样就可以将ActionFilter当做属性来用,同时继承了IActionFilter接口,这就要求我们实现两个方法:OnActionExecutedOnActionExecuting 两个方法的执行顺序分别是控制器(动作方法)被执行后和执行前。因为我们需要在所有的控制器里面使用UserId, 所以我们在OnActionExecuting 执行相应的逻辑操作。
ActionExecutedContext 作为一个OnActionExecuting方法的参数,可以得到控制器本身,我们将控制器转化为 ApiController  也就是上文定义的那个抽象类,这样就可以操作里面定义的UserId 了。因为我用的JWT验证,所以第二行的逻辑可以获取到登录用的UserId。对于ClaimTypes.NameIdentifier 这个属性 可以在生成Toke的时候用登录用户的UserId赋值,这样就可以作为有效信息存到Token中去便于解析。

1public static string CreateToken(JwtTokenModel tokenModel)
 2
 3            var claims= new []
 4                new Claim("Id",tokenModel.Id.ToString()),
 5                new Claim("CustomerNo",tokenModel.CustomerNo),
 6                new Claim("CustomerName",tokenModel.CustomerName),
 7                new Claim(ClaimTypes.NameIdentifier,tokenModel.CustomerNo) // ClaimTypes.NameIdentifier类型值为用户Id
 8            ;
 9            // 生成密钥
10            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(tokenModel.Security));
11            var creds = new SigningCredentials(key,SecurityAlgorithms.HmacSha256); 
12
13            var token =new JwtSecurityToken(
14                issuer:tokenModel.Issuer,
15                audience:tokenModel.Audience,
16                expires:DateTime.Now.AddDays(tokenModel.Expires),
17                signingCredentials:creds,
18                claims:claims
19            );
20
21            //生成token
22            var accessToken =new JwtSecurityTokenHandler().WriteToken(token);
23            return accessToken;
24

示例展示

1    /// <summary>
 2    /// 测试控制器  继承自定义的ApiController
 3    /// </summary>
 4    public class TestController : ApiController
 5    
 6        [HttpGet]
 7        public void GetUserId()
 8        
 9            // 直接获取到用户访问的用户Id 
10            // 后续需要UserId传参调用服务的时候就不需要重新获取了用户Id了
11            System.Console.WriteLine("用户Id:"+UserId); // 控制台可以打印出 访问登录用户的UserId
12        
13    

以上是关于C#/.NET 日常开发技巧JWT+ActionFilter 简便控制器代码的主要内容,如果未能解决你的问题,请参考以下文章

鉴权/授权一步一步实现一个简易JWT鉴权

鉴权/授权基于角色的简单授权认证

C#/.NET.NET6中全局异常处理

嵌入式开发常用技巧及C/C++知识

C#/.NET不用AutoMapper,我用啥呢?

鉴权/授权自定义一个身份认证Handler