前言
在前面我讲过基于token的权限认证,然后前几天有小伙伴私信我,怎么做一个身份认证也就是授权。
在Asp.net Core常见的授权方式有:
基于角色的授权,
有基于声明的授权,
有基于策略的授权, 这三种授权我就不做过多介绍了,大家可以去查阅官网, https://docs.microsoft.com/en-us/aspnet/core/security/authorization/claims?view=aspnetcore-6.0
自定义授权
今天给大家带来的是自定义授权!
那大家需要了解一下什么是授权,授权就是确定用户身份的过程,其本质就是拥有某些特性的用户会有权限访问某个资源或执行某个操作
那根据这个原理我们可以就可以开始设计了,我们在设计前我们要明白我们所做的系统 都有什么角色,比如我们现在设计一个基于管理员和普通用户的授权。
我们首先肯定要定义一个权限策略,
public class PermissionRequirement : IAuthorizationRequirement{public string _permissionName { get; }public PermissionRequirement(string PermissionName){_permissionName = PermissionName;}}
然后我们将 自定义要求添加到策略在startup类中添加。此外,还需要在 IAuthorizationHandler 类型的范围内向 DI 系统注册新的处理程序:
public void ConfigureServices(IServiceCollection services){services.AddControllers(o =>{// o.Filters.Add<ApiAuthorize>();o.Filters.Add<MyAuthentication>();});services.AddAuthentication();//基于自定义策略授权services.AddAuthorization(options =>{options.AddPolicy("Admin",policy => policy.Requirements.Add(new PermissionRequirement("Admin")));options.AddPolicy("Client",policy => policy.Requirements.Add(new PermissionRequirement("Client")));});services.AddHttpContextAccessor();services.AddScoped<IAuthorizationHandler, PermissionRequirementHandler>();}
我们注册好了之后肯定要把自定义策略用在控制器上 比如说这个 我们只允许管理员访问。
[HttpGet("GetUserInformation")][Authorize(Policy = "Admin")]public IActionResult GetUserInformation(){return Ok(new { Name="123",Age=18,Sex="性别"});}
那么问题来了 我们怎么去处理这些策略啦,
在Asp.net Core中已经帮我们内置了授权处理的基类AuthorizationHandler,只需要继承他即可, 在Asp.net Core中的授权处理基类是获取不到我们的HTTPContext,所以我们需要借助注入IHttpContextAccessor拿到我们的HTTPContext的上下文
然后在我们的StartUp类里面 注入即可
services.AddHttpContextAccessor();
那我们再看授权处理类
public class PermissionRequirementHandler : AuthorizationHandler<PermissionRequirement>{private readonly IHttpContextAccessor _httpContextAccessor;public PermissionRequirementHandler(IHttpContextAccessor httpContextAccessor){_httpContextAccessor = httpContextAccessor;}protected async override Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement){HttpContext httpContext = _httpContextAccessor.HttpContext;}
那根据我们定义的PermissionRequirement权限策略可以获取到调用的方法具有什么策略。
那我们怎么获取当前用户具有那些角色呢?
所以我们需要改造一下我们获取token的接口 我们在获取Token的时候,把token值写入缓存时,我们把缓存当作我们的key值,用户信息当成Value值 我们定义一个用户信息Model,我这里偷懒了 只需要用户的Code和sub
public class TokenModel{public string UserCode { get; set; }public string Sub { get; set; }}[HttpGet("GetToken")][MyNoAuthentication]public IActionResult GetToken(string UserCode){string token= AESEncrypt.Encrypt(UserCode);TokenModel tokenModel = new TokenModel();tokenModel.UserCode = UserCode;tokenModel.Sub = UserCode=="1"?"Admin":"Client";MemoryCacheHelper.AddMemoryCache(token, tokenModel);return Ok(token);}
然后再获取Token的时候将值写入到缓存中,最后就像我们判断用户token有效没有来判断用户是否具有权限访问
public class PermissionRequirementHandler : AuthorizationHandler<PermissionRequirement>{private readonly IHttpContextAccessor _httpContextAccessor;public PermissionRequirementHandler(IHttpContextAccessor httpContextAccessor){_httpContextAccessor = httpContextAccessor;}protected async override Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement){HttpContext httpContext = _httpContextAccessor.HttpContext;var authorize = httpContext.Request.Headers["MyAuthentication"];if (string.IsNullOrEmpty(authorize)){await httpContext.Response.WriteAsync("请求参数不能为空");context.Fail();}if (!MemoryCacheHelper.Exists(authorize)){await httpContext.Response.WriteAsync("无效的授权信息或者授权信息已过期"); context.Fail();}TokenModel tokenModel= (TokenModel)MemoryCacheHelper.Get(authorize);if (tokenModel.Sub == requirement._permissionName){context.Succeed(requirement);}else {await httpContext.Response.WriteAsync("服务端拒绝访问:当前身份没有权限访问,请联系管理员开放权限");context.Fail();}}}
测试
我们测试一下
普通用户
管理员