您现在的位置是:网站首页> 编程资料编程资料
asp.net core项目授权流程详解_实用技巧_
2023-05-24
338人已围观
简介 asp.net core项目授权流程详解_实用技巧_
在上一篇 聊聊 asp.net core 认证和授权 中我们提到了认证和授权的基本概念,以及认证和授权的关系及他们之间的协同工作流程,在这篇文章中,我将通过分析asp.net core 3.1 授权流程的源码给大家介绍asp.net core 框架里面授权流程的具体实现逻辑,本文并非讲解具体的实战应用,建议在使用过asp.net core 授权框架后在来阅读本文收货会更多。
一、授权流程用到的主要的几个接口及类
- IAuthorizationService,默认实现类: DefaultAuthorizationService,该类主要职责就是遍历所有注入到容器的实现了IAuthorizationHandler接口的服务,并调用其HandleAsync方法来进行授权检查,也就是说该类的主要职责就是检查授权策略(AuthorizationPolicy)是否校验通过,校验通过则授权成功,否则授权失败。
- IAuthorizationPolicyProvider,默认实现类:DefaultAuthorizationPolicyProvider,负责根据策略名称提供授权策略,以及提供默认授权策略等,内部就是从AuthorizationOptions内部的策略字典(Dictionary)中直接获取。
- IAuthorizationHandlerProvider,默认实现类:DefaultAuthorizationHandlerProvider,用于获取已经注册到容器中的所有实现了IAuthorizationHandler的授权服务,所有授权服务是通过构造函数依赖注入实现的(IEnumerable
作为构造函数入参) - IAuthorizationHandler,默认实现类:PassThroughAuthorizationHandler,该类是AddAuthorization的时候默认注册的授权处理程序(实现IAuthorizationHandler接口),用于遍历授权策略中包含的所有的实现了IAuthorizationHandler的Requirement类,并调用其HandleAsync方法进行检查Requirement授权是否成功,这里的Requirement类是指实现了AuthorizationHandler
抽象基类的Requirement类。 - IAuthorizationEvaluator,默认实现类:DefaultAuthorizationEvaluator,执行授权流程,并对授权检查结果进行检查,如果是授权失败,并且未认证则返回401,如果是授权失败,但认证通过,则返回403
- IAuthorizationHandlerContextFactory,默认实现类:DefaultAuthorizationHandlerContextFactory,用于创建AuthorizationHandlerContext对象的工厂类,AuthorizationHandlerContext 上下文中包含每次授权流程中要被校验的所有的Requirement类。
- AuthorizationMiddleware,负责对请求进行授权检查的中间件.
- AuthorizationOptions类,内部维护了一个策略字典(Dictionary)用于存储所有注册的策略,key为策略名称,value为具体的策略(AuthorizationPolicy)
- AuthorizationPolicy类,策略的具体表示,主要包含 AuthenticationSchemes 和 Requirements属性,AuthenticationSchemes 表示执行该策略时采用什么认证方案进行身分认证, Requirements 表示该策略要验证的Requirement列表
- AuthorizationPolicyBuilder类,该类主要是用于构建AuthorizationPolicy类,也就是用于构建具体策略的类,通过该类,可以指定该授权策略需要采用什么认证方案进行认证,以及授权检查时需要满足那些Requirement。
二、授权服务注册流程
首先找到 PolicyServiceCollectionExtensions 类,这个扩展方法类,对IServiceCollection接口进行了扩展,因此我们可以在Startup.cs 的ConfigureService方法中直接
services.AddAuthorization来注册 授权相关服务。
// Microsoft.Extensions.DependencyInjection.PolicyServiceCollectionExtensions using System; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization.Policy; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; public static class PolicyServiceCollectionExtensions { public static IServiceCollection AddAuthorizationPolicyEvaluator(this IServiceCollection services) { if (services == null) { throw new ArgumentNullException("services"); } services.TryAddSingleton(); services.TryAdd(ServiceDescriptor.Transient()); return services; } //当不想在应用程序中注册授权策略时,直接调用此方法即可。 public static IServiceCollection AddAuthorization(this IServiceCollection services) { return services.AddAuthorization(null); } //当需要在应用程序中注册特定的授权策略时,调用这个方法,configure为Action类型的委托方法,入参为AuthorizationOptions 授权配置类, //可通过该类的AddPolicy方法来进行授权策略的注册。 public static IServiceCollection AddAuthorization(this IServiceCollection services, Action configure) { if (services == null) { throw new ArgumentNullException("services"); } services.AddAuthorizationCore(configure); services.AddAuthorizationPolicyEvaluator(); return services; } } 可以看到,内部调用了AddAuthorizationCore方法,这个扩展方法定义在:AuthorizationServiceCollectionExtensions 类
// Microsoft.Extensions.DependencyInjection.AuthorizationServiceCollectionExtensions using System; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization.Infrastructure; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; public static class AuthorizationServiceCollectionExtensions { public static IServiceCollection AddAuthorizationCore(this IServiceCollection services) { if (services == null) { throw new ArgumentNullException("services"); } //以下这些服务便是上文中介绍的授权流程用到的主要服务类,及具体的默认实现类。 services.TryAdd(ServiceDescriptor.Transient()); services.TryAdd(ServiceDescriptor.Transient()); services.TryAdd(ServiceDescriptor.Transient()); services.TryAdd(ServiceDescriptor.Transient()); services.TryAdd(ServiceDescriptor.Transient()); services.TryAddEnumerable(ServiceDescriptor.Transient()); return services; } public static IServiceCollection AddAuthorizationCore(this IServiceCollection services, Action configure) { if (services == null) { throw new ArgumentNullException("services"); } //这里的configure便是我们应用程序传入的委托回调方法,用于向AuthorizationOptions类添加授权策略。 if (configure != null) { services.Configure(configure); } return services.AddAuthorizationCore(); } } 下面这个是应用注册授权策略的常规流程的一个例子:
public void ConfigureServices(IServiceCollection services) { //添加授权相关服务。 services.AddAuthorization(options => { //往AuthorizationOptions类中添加名为:adminPolicy的授权策略。 //参数:authorizationPolicyBuilder 为AuthorizationPolicyBuilder类。 options.AddPolicy("adminPolicy", authorizationPolicyBuilder => { authorizationPolicyBuilder.AddAuthenticationSchemes("Cookie"); //表示用户必须属于admin角色才能访问。 authorizationPolicyBuilder.AddRequirements(new RolesAuthorizationRequirement(new string[] { "admin" })); //表示用户声明中包含名为cardNo的 Claim,并且值为23902390才允许访问,也就是 HttpContext.User.Claims 中包含cardNo,并且值为相应值才能访问。 authorizationPolicyBuilder.Requirements.Add(new ClaimsAuthorizationRequirement("cardNo", new string[] { "23902390" })); //表示用用户名必须是admin才允许访问,AuthorizationBuilder中海油RequireClaim、RequireRole等方法。 authorizationPolicyBuilder.RequireUserName("admin"); //只有以上3个Requirement同时满足,该策略才算授权成功 }); }); }三、启用授权流程
第二个步骤仅仅是将授权流程中用到的相关服务注册到依赖注入容器中,以及应用配置授权策略,真正的启用授权流程则需要通过 Startup.cs 类中的Configure方法中调用 app.UseAuthorization(); 进行开启,本质上就是将 AuthorizationMiddleware 授权中间件,注册到中间件管道中。
// Microsoft.AspNetCore.Builder.AuthorizationAppBuilderExtensions using System; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization.Policy; using Microsoft.AspNetCore.Builder; public static class AuthorizationAppBuilderExtensions { public static IApplicationBuilder UseAuthorization(this IApplicationBuilder app) { if (app == null) { throw new ArgumentNullException("app"); } VerifyServicesRegistered(app); //注册授权中间件。AuthorizationMiddleware return app.UseMiddleware(Array.Empty 要看授权流程的具体执行逻辑,我们还是要看AuthorizationMiddleware类。
// Microsoft.AspNetCore.Authorization.AuthorizationMiddleware using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization.Policy; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; public class AuthorizationMiddleware { private const string AuthorizationMiddlewareInvokedWithEndpointKey = "__AuthorizationMiddlewareWithEndpointInvoked"; private static readonly object AuthorizationMiddlewareWithEndpointInvokedValue = new object(); private readonly RequestDelegate _next; private readonly IAuthorizationPolicyProvider _policyProvider; public AuthorizationMiddleware(RequestDelegate next, IAuthorizationPolicyProvider policyProvider) { _next = next ?? throw new ArgumentNullException("next"); _policyProvider = policyProvider ?? throw new ArgumentNullException("policyProvider"); } public async Task Invoke(HttpContext context) { if (context == null) { throw new ArgumentNullException("context"); } Endpoint endpoint = context.GetEndpoint(); if (endpoint != null) { context.Items["__AuthorizationMiddlewareWithEndpointInvoked"] = AuthorizationMiddlewareWithEndpointInvokedValue; } //这里获取Controller或者Action上标注的一个或者多个[Authorize]特性, //每个Authorize特性都有一个Policy属性,用于指定一个或者多个授权策略,表示这些策略必须同时满足才算授权通过, //Roles属性则用于指定用户角色列表,表示用户必须属于这些角色才允许访问,这里的角色控制最终其实也是转换为策略的形式去控制。 //AuthenticationSchemes则用于指定认证方案列表,表示用户访问该资源时采用这些认证方案进行身份认证 //如:[Authorize(AuthenticationSchemes = "cookie", Policy = "adminPolicy", Roles = "admin")] IReadOnlyList authorizeData = endpoint?.Metadata.GetOrderedMetadata() ?? Array.Empty(); //以下将Controller或者Action上的一个或者多个[Authorize]特性上指定的访问该资源所需要的满足的Policy授权策略列表, //及访问该资源时用户所需具备的角色列表,以及访问该资源时将采用的认证方案合并到一个策略对象中去, //也就是说最终返回的这个授权策略包含了访问该资源所需要满足的所有授权策略列表,用户所必须具备的所有用户角色列表,以及采用的所有认证方案列表。 AuthorizationPolicy policy = await AuthorizationPolicy.CombineAsync(_policyProvider, authorizeData); if (policy == null) { await _next(context); return; } IPolicyEvaluator policyEvaluator = context.RequestServices.GetRequiredService(); //这里首先对当前访问者进行用户身份的认证,认证方案采用的是上面合并过后的一个或者多个认证方案进行认证。 AuthenticateResult authenticationResult = await policyEvaluator.AuthenticateAsync(policy, context); //如果允许匿名访问,则不再进行授权检查。 if (endpoint?.Metadata.GetMetadata() != null) { await _next(context); return; } //这里对policy中包含的所有授权策略进行一一检查,如果全部验证通过,则表示授权成功,允许用户访问, //否则根据用户是否已经登录来判定是让用户登录(401-Challenged)还是提示用户没权限访问(403-Forbiden) PolicyAuthorizationResu
相关内容
- .NET Core Web APi类库内嵌运行的方法_实用技巧_
- ASP.NET MVC使用Session会话保持表单状态_实用技巧_
- NetCore 配置Swagger的详细代码_实用技巧_
- asp.net core服务限制堆内存大小的操作方法_实用技巧_
- asp.net web api2设置默认启动登录页面的方法_实用技巧_
- ASP.NET MVC实现下拉框多选_实用技巧_
- ASP.NET MVC使用Quartz.NET执行定时任务_实用技巧_
- ASP.NET MVC视图页使用jQuery传递异步数据的几种方式详解_实用技巧_
- .NET 实现启动时重定向程序运行路径及 Windows 服务运行模式部署的方法_实用技巧_
- ASP.NET MVC通过勾选checkbox更改select的内容_实用技巧_
点击排行
本栏推荐
