前面介绍了认证中间件,下面看一下授权中间件。
app.UseAuthorization();
授权中间件是这个,前面我们提及到认证中间件并不会让整个中间件停止。
认证中间件就两个作用,我们的认证方案如果实现了IAuthenticationRequestHandler,那么会调用HandleRequestAsync判断是否继续运行。
然后我们设置默认的认证方案,那么会调用其认证方案的具体的处理,如果认证成功,那么会赋予context.User。
但是在这个认证中间件如果认证不过,那么也会继续往下运行,因为我们还有其他一些不需要认证就可以访问的方法,所以中间件不能一棒子打死。
这个认证中间件的作用主要部分是如果这个用户能通过默认的认证方案,那么就给他打上了一个标签,这个标签就是context.User。
context.user 是public abstract ClaimsPrincipal User { get; set; },里面存着用户的一些信息。 认证中间件做的是这件事,那么看下授权中间件干的是什么吧。
public AuthorizationMiddleware( RequestDelegate next, IAuthorizationPolicyProvider policyProvider) { RequestDelegate requestDelegate = next; if (requestDelegate == null) throw new ArgumentNullException(nameof (next)); this._next = requestDelegate; IAuthorizationPolicyProvider authorizationPolicyProvider = policyProvider; if (authorizationPolicyProvider == null) throw new ArgumentNullException(nameof (policyProvider)); this._policyProvider = authorizationPolicyProvider; }
里面有一个IAuthorizationPolicyProvider,这个就是用来管理授权策略的管理的,里面不出所料应该就是授权策略的增删改查了。
public interface IAuthorizationPolicyProvider { Task<AuthorizationPolicy?> GetPolicyAsync(string policyName); Task<AuthorizationPolicy> GetDefaultPolicyAsync(); Task<AuthorizationPolicy?> GetFallbackPolicyAsync(); }
好吧,里面只有查询,并没有增加,看下增加应该在别的地方。
经过我们前面的源码查看呢,我们发现provider 结尾的是提供的意思,xxProvoder,就是为我们提供什么,那么里面就一定有get之类的东西。
可能xxProvoder里面也有增加和删除和改,但是也不一定,看设计复杂性,如果设计复杂一点,那么增加删除和改会放到另外一个地方,那么这个就是设计到另外一个地方,看了是相对来说复杂一点。
那么来看一下invoke:
public async Task Invoke(HttpContext context) { Endpoint endpoint; AuthorizationPolicy policy; IPolicyEvaluator policyEvaluator; try { if (context == null) throw new ArgumentNullException(nameof (context)); endpoint = context.GetEndpoint(); if (endpoint != null) context.Items[(object) "__AuthorizationMiddlewareWithEndpointInvoked"] = AuthorizationMiddleware.AuthorizationMiddlewareWithEndpointInvokedValue; Endpoint endpoint1 = endpoint; TaskAwaiter<AuthorizationPolicy> awaiter1 = AuthorizationPolicy.CombineAsync(this._policyProvider, (IEnumerable<IAuthorizeData>) ((endpoint1 != null ? (object) endpoint1.Metadata.GetOrderedMetadata<IAuthorizeData>() : (object) null) ?? (object) Array.Empty<IAuthorizeData>())).GetAwaiter(); int num; if (!awaiter1.IsCompleted) { // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003E1__state = num = 0; TaskAwaiter<AuthorizationPolicy> taskAwaiter = awaiter1; // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003Et__builder.AwaitUnsafeOnCompleted<TaskAwaiter<AuthorizationPolicy>, AuthorizationMiddleware.\u003CInvoke\u003Ed__6>(ref awaiter1, this); return; } policy = awaiter1.GetResult(); TaskAwaiter taskAwaiter1; if (policy == null) { TaskAwaiter awaiter2 = this._next(context).GetAwaiter(); if (!awaiter2.IsCompleted) { // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003E1__state = num = 1; taskAwaiter1 = awaiter2; // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003Et__builder.AwaitUnsafeOnCompleted<TaskAwaiter, AuthorizationMiddleware.\u003CInvoke\u003Ed__6>(ref awaiter2, this); return; } awaiter2.GetResult(); } else { policyEvaluator = context.RequestServices.GetRequiredService<IPolicyEvaluator>(); TaskAwaiter<AuthenticateResult> awaiter2 = policyEvaluator.AuthenticateAsync(policy, context).GetAwaiter(); if (!awaiter2.IsCompleted) { // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003E1__state = num = 2; TaskAwaiter<AuthenticateResult> taskAwaiter2 = awaiter2; // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003Et__builder.AwaitUnsafeOnCompleted<TaskAwaiter<AuthenticateResult>, AuthorizationMiddleware.\u003CInvoke\u003Ed__6>(ref awaiter2, this); return; } AuthenticateResult result1 = awaiter2.GetResult(); if (endpoint?.Metadata.GetMetadata<IAllowAnonymous>() != null) { TaskAwaiter awaiter3 = this._next(context).GetAwaiter(); if (!awaiter3.IsCompleted) { // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003E1__state = num = 3; taskAwaiter1 = awaiter3; // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003Et__builder.AwaitUnsafeOnCompleted<TaskAwaiter, AuthorizationMiddleware.\u003CInvoke\u003Ed__6>(ref awaiter3, this); return; } awaiter3.GetResult(); } else { bool isEnabled; object resource = !(AppContext.TryGetSwitch("Microsoft.AspNetCore.Authorization.SuppressUseHttpContextAsAuthorizationResource", out isEnabled) & isEnabled) ? (object) context : (object) endpoint; TaskAwaiter<PolicyAuthorizationResult> awaiter3 = policyEvaluator.AuthorizeAsync(policy, result1, context, resource).GetAwaiter(); if (!awaiter3.IsCompleted) { // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003E1__state = num = 4; TaskAwaiter<PolicyAuthorizationResult> taskAwaiter2 = awaiter3; // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003Et__builder.AwaitUnsafeOnCompleted<TaskAwaiter<PolicyAuthorizationResult>, AuthorizationMiddleware.\u003CInvoke\u003Ed__6>(ref awaiter3, this); return; } PolicyAuthorizationResult result2 = awaiter3.GetResult(); TaskAwaiter awaiter4 = context.RequestServices.GetRequiredService<IAuthorizationMiddlewareResultHandler>().HandleAsync(this._next, context, policy, result2).GetAwaiter(); if (!awaiter4.IsCompleted) { // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003E1__state = num = 5; taskAwaiter1 = awaiter4; // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003Et__builder.AwaitUnsafeOnCompleted<TaskAwaiter, AuthorizationMiddleware.\u003CInvoke\u003Ed__6>(ref awaiter4, this); return; } awaiter4.GetResult(); } } } catch (Exception ex) { // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003E1__state = -2; endpoint = (Endpoint) null; policy = (AuthorizationPolicy) null; policyEvaluator = (IPolicyEvaluator) null; // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003Et__builder.SetException(ex); return; } // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003E1__state = -2; endpoint = (Endpoint) null; policy = (AuthorizationPolicy) null; policyEvaluator = (IPolicyEvaluator) null; // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003Et__builder.SetResult(); }
一段一段来看。
Endpoint endpoint; AuthorizationPolicy policy; IPolicyEvaluator policyEvaluator; try { if (context == null) throw new ArgumentNullException(nameof (context)); endpoint = context.GetEndpoint(); if (endpoint != null) context.Items[(object) "__AuthorizationMiddlewareWithEndpointInvoked"] = AuthorizationMiddleware.AuthorizationMiddlewareWithEndpointInvokedValue; Endpoint endpoint1 = endpoint; TaskAwaiter<AuthorizationPolicy> awaiter1 = AuthorizationPolicy.CombineAsync(this._policyProvider, (IEnumerable<IAuthorizeData>) ((endpoint1 != null ? (object) endpoint1.Metadata.GetOrderedMetadata<IAuthorizeData>() : (object) null) ?? (object) Array.Empty<IAuthorizeData>())).GetAwaiter();
这一段呢,我们可以看到主要是获取我们的授权策略。
首先通过endpoint = context.GetEndpoint(); 获取我们的路由终点。
不知道各位对endpoint 的了解有多少呢? 后面会整理一下进行介绍,主要介绍一下app.UseRouting();和app.UseEndpoints();这两个东西来介绍一下的,现在只需要知道Endpoint装载这一些我们的路由信息以及属性特征。
endpoint1.Metadata.GetOrderedMetadata
元数据(Metadata),又称中介数据、中继数据,为描述数据的数据(data about data),主要是描述数据属性(property)的信息,用来支持如指示存储位置、历史数据、资源查找、文件记录等功能。元数据算是一种电子式目录,为了达到编制目录的目的,必须在描述并收藏数据的内容或特色,进而达成协助数据检索的目的。都柏林核心集(Dublin Core Metadata Initiative,DCMI)是元数据的一种应用,是1995年2月由国际图书馆电脑中心(OCLC)和美国国家超级计算应用中心(National Center for Supercomputing Applications,NCSA)所联合赞助的研讨会,在邀请52位来自图书馆员、电脑专家,共同制定规格,创建一套描述网络上电子文件之特征。
这里就是获取到我们的属性了,获取到我们的IAuthorizeData 属性,看到这个东西是不是特别熟系?
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)] public class AuthorizeAttribute : Attribute, IAuthorizeData { public AuthorizeAttribute() { } public AuthorizeAttribute(string policy) { this.Policy = policy; } public string? Policy { get; set; } public string? Roles { get; set; } public string? AuthenticationSchemes { get; set; } }
是的,它就会获取到我们配置的权限方案。
好的,那么我们看下AuthorizationPolicy.CombineAsync这个东西。
public static async Task<AuthorizationPolicy?> CombineAsync( IAuthorizationPolicyProvider policyProvider, IEnumerable<IAuthorizeData> authorizeData) { // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field int num1 = (^this).\u003C\u003E1__state; AuthorizationPolicyBuilder policyBuilder; AuthorizationPolicy result1; try { if (policyProvider == null) throw new ArgumentNullException(nameof (policyProvider)); if (authorizeData == null) throw new ArgumentNullException(nameof (authorizeData)); bool flag1 = false; if (authorizeData is IList<IAuthorizeData> authorizeDataList) flag1 = authorizeDataList.Count == 0; policyBuilder = (AuthorizationPolicyBuilder) null; TaskAwaiter<AuthorizationPolicy> taskAwaiter; if (!flag1) { IEnumerator<IAuthorizeData> enumerator = authorizeData.GetEnumerator(); try { while (enumerator.MoveNext()) { IAuthorizeData authorizeDatum = enumerator.Current; if (policyBuilder == null) policyBuilder = new AuthorizationPolicyBuilder(Array.Empty<string>()); bool flag2 = true; TaskAwaiter<AuthorizationPolicy> awaiter; if (!string.IsNullOrWhiteSpace(authorizeDatum.Policy)) { awaiter = policyProvider.GetPolicyAsync(authorizeDatum.Policy).GetAwaiter(); if (!awaiter.IsCompleted) { // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003E1__state = num1 = 0; taskAwaiter = awaiter; // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003Et__builder.AwaitUnsafeOnCompleted<TaskAwaiter<AuthorizationPolicy>, AuthorizationPolicy.\u003CCombineAsync\u003Ed__9>(ref awaiter, this); return; } AuthorizationPolicy result2 = awaiter.GetResult(); if (result2 == null) throw new InvalidOperationException(Resources.FormatException_AuthorizationPolicyNotFound((object) authorizeDatum.Policy)); policyBuilder.Combine(result2); flag2 = false; } string[] strArray1 = authorizeDatum.Roles?.Split(',', StringSplitOptions.None); if (strArray1 != null && strArray1.Length != 0) { policyBuilder.RequireRole(((IEnumerable<string>) strArray1).Where<string>((Func<string, bool>) (r => !string.IsNullOrWhiteSpace(r))).Select<string, string>((Func<string, string>) (r => r.Trim()))); flag2 = false; } string[] strArray2 = authorizeDatum.AuthenticationSchemes?.Split(',', StringSplitOptions.None); if (strArray2 != null && strArray2.Length != 0) { foreach (string str in strArray2) { if (!string.IsNullOrWhiteSpace(str)) policyBuilder.AuthenticationSchemes.Add(str.Trim()); } } if (flag2) { AuthorizationPolicyBuilder authorizationPolicyBuilder = policyBuilder; awaiter = policyProvider.GetDefaultPolicyAsync().GetAwaiter(); if (!awaiter.IsCompleted) { // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003E1__state = num1 = 1; taskAwaiter = awaiter; // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003Et__builder.AwaitUnsafeOnCompleted<TaskAwaiter<AuthorizationPolicy>, AuthorizationPolicy.\u003CCombineAsync\u003Ed__9>(ref awaiter, this); return; } authorizationPolicyBuilder.Combine(awaiter.GetResult()); authorizationPolicyBuilder = (AuthorizationPolicyBuilder) null; } authorizeDatum = (IAuthorizeData) null; } } finally { if (num1 < 0 && enumerator != null) enumerator.Dispose(); } enumerator = (IEnumerator<IAuthorizeData>) null; } if (policyBuilder == null) { TaskAwaiter<AuthorizationPolicy> awaiter = policyProvider.GetFallbackPolicyAsync().GetAwaiter(); if (!awaiter.IsCompleted) { int num2; // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003E1__state = num2 = 2; taskAwaiter = awaiter; // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003Et__builder.AwaitUnsafeOnCompleted<TaskAwaiter<AuthorizationPolicy>, AuthorizationPolicy.\u003CCombineAsync\u003Ed__9>(ref awaiter, this); return; } AuthorizationPolicy result2 = awaiter.GetResult(); if (result2 != null) { result1 = result2; goto label_43; } } result1 = policyBuilder?.Build(); } catch (Exception ex) { // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003E1__state = -2; policyBuilder = (AuthorizationPolicyBuilder) null; // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003Et__builder.SetException(ex); return; } label_43: // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003E1__state = -2; policyBuilder = (AuthorizationPolicyBuilder) null; // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003Et__builder.SetResult(result1); }
先贴一下的确有点长,但是我们只看正常授权部分其他不看哈。
int num1 = (^this).\u003C\u003E1__state; AuthorizationPolicyBuilder policyBuilder; AuthorizationPolicy result1; try { if (policyProvider == null) throw new ArgumentNullException(nameof (policyProvider)); if (authorizeData == null) throw new ArgumentNullException(nameof (authorizeData)); bool flag1 = false; if (authorizeData is IList<IAuthorizeData> authorizeDataList) flag1 = authorizeDataList.Count == 0; policyBuilder = (AuthorizationPolicyBuilder) null; TaskAwaiter<AuthorizationPolicy> taskAwaiter;
这一段是做一些逻辑判断,判断我们是否配置了授权策略。
if (!flag1) { IEnumerator<IAuthorizeData> enumerator = authorizeData.GetEnumerator(); try { while (enumerator.MoveNext()) { IAuthorizeData authorizeDatum = enumerator.Current; if (policyBuilder == null) policyBuilder = new AuthorizationPolicyBuilder(Array.Empty<string>()); bool flag2 = true; TaskAwaiter<AuthorizationPolicy> awaiter; if (!string.IsNullOrWhiteSpace(authorizeDatum.Policy)) { awaiter = policyProvider.GetPolicyAsync(authorizeDatum.Policy).GetAwaiter(); if (!awaiter.IsCompleted) { // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003E1__state = num1 = 0; taskAwaiter = awaiter; // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003Et__builder.AwaitUnsafeOnCompleted<TaskAwaiter<AuthorizationPolicy>, AuthorizationPolicy.\u003CCombineAsync\u003Ed__9>(ref awaiter, this); return; } AuthorizationPolicy result2 = awaiter.GetResult(); if (result2 == null) throw new InvalidOperationException(Resources.FormatException_AuthorizationPolicyNotFound((object) authorizeDatum.Policy)); policyBuilder.Combine(result2); flag2 = false; } string[] strArray1 = authorizeDatum.Roles?.Split(',', StringSplitOptions.None); if (strArray1 != null && strArray1.Length != 0) { policyBuilder.RequireRole(((IEnumerable<string>) strArray1).Where<string>((Func<string, bool>) (r => !string.IsNullOrWhiteSpace(r))).Select<string, string>((Func<string, string>) (r => r.Trim()))); flag2 = false; } string[] strArray2 = authorizeDatum.AuthenticationSchemes?.Split(',', StringSplitOptions.None); if (strArray2 != null && strArray2.Length != 0) { foreach (string str in strArray2) { if (!string.IsNullOrWhiteSpace(str)) policyBuilder.AuthenticationSchemes.Add(str.Trim()); } } if (flag2) { AuthorizationPolicyBuilder authorizationPolicyBuilder = policyBuilder; awaiter = policyProvider.GetDefaultPolicyAsync().GetAwaiter(); if (!awaiter.IsCompleted) { // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003E1__state = num1 = 1; taskAwaiter = awaiter; // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003Et__builder.AwaitUnsafeOnCompleted<TaskAwaiter<AuthorizationPolicy>, AuthorizationPolicy.\u003CCombineAsync\u003Ed__9>(ref awaiter, this); return; } authorizationPolicyBuilder.Combine(awaiter.GetResult()); authorizationPolicyBuilder = (AuthorizationPolicyBuilder) null; } authorizeDatum = (IAuthorizeData) null; } } finally { if (num1 < 0 && enumerator != null) enumerator.Dispose(); } enumerator = (IEnumerator<IAuthorizeData>) null; }
这一段是如果我们配置了授权策略,那么如何处理哈,里面通过while 会处理每一个授权策略。
IAuthorizeData authorizeDatum = enumerator.Current; if (policyBuilder == null) policyBuilder = new AuthorizationPolicyBuilder(Array.Empty<string>()); bool flag2 = true; TaskAwaiter<AuthorizationPolicy> awaiter; if (!string.IsNullOrWhiteSpace(authorizeDatum.Policy)) { awaiter = policyProvider.GetPolicyAsync(authorizeDatum.Policy).GetAwaiter(); if (!awaiter.IsCompleted) { // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003E1__state = num1 = 0; taskAwaiter = awaiter; // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003Et__builder.AwaitUnsafeOnCompleted<TaskAwaiter<AuthorizationPolicy>, AuthorizationPolicy.\u003CCombineAsync\u003Ed__9>(ref awaiter, this); return; } AuthorizationPolicy result2 = awaiter.GetResult(); if (result2 == null) throw new InvalidOperationException(Resources.FormatException_AuthorizationPolicyNotFound((object) authorizeDatum.Policy)); policyBuilder.Combine(result2); flag2 = false; }
这个是找出策略模式的授权方案,然后存储到AuthorizationPolicyBuilder中。
string[] strArray1 = authorizeDatum.Roles?.Split(',', StringSplitOptions.None); if (strArray1 != null && strArray1.Length != 0) { policyBuilder.RequireRole(((IEnumerable<string>) strArray1).Where<string>((Func<string, bool>) (r => !string.IsNullOrWhiteSpace(r))).Select<string, string>((Func<string, string>) (r => r.Trim()))); flag2 = false; }
这里是找出基于角色的授权,然后放入到AuthorizationPolicyBuilder 中。
string[] strArray2 = authorizeDatum.AuthenticationSchemes?.Split(',', StringSplitOptions.None); if (strArray2 != null && strArray2.Length != 0) { foreach (string str in strArray2) { if (!string.IsNullOrWhiteSpace(str)) policyBuilder.AuthenticationSchemes.Add(str.Trim()); } }
这上面是找出认证方式,然后加入到AuthorizationPolicyBuilder 的AuthenticationSchemes中。
if (flag2) { AuthorizationPolicyBuilder authorizationPolicyBuilder = policyBuilder; awaiter = policyProvider.GetDefaultPolicyAsync().GetAwaiter(); if (!awaiter.IsCompleted) { // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003E1__state = num1 = 1; taskAwaiter = awaiter; // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003Et__builder.AwaitUnsafeOnCompleted<TaskAwaiter<AuthorizationPolicy>, AuthorizationPolicy.\u003CCombineAsync\u003Ed__9>(ref awaiter, this); return; } authorizationPolicyBuilder.Combine(awaiter.GetResult()); authorizationPolicyBuilder = (AuthorizationPolicyBuilder) null; }
这里就是如果我们没有指明我们的授权方式,那么将使用默认的授权验证方式。
if (policyBuilder == null) { TaskAwaiter<AuthorizationPolicy> awaiter = policyProvider.GetFallbackPolicyAsync().GetAwaiter(); if (!awaiter.IsCompleted) { int num2; // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003E1__state = num2 = 2; taskAwaiter = awaiter; // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003Et__builder.AwaitUnsafeOnCompleted<TaskAwaiter<AuthorizationPolicy>, AuthorizationPolicy.\u003CCombineAsync\u003Ed__9>(ref awaiter, this); return; } AuthorizationPolicy result2 = awaiter.GetResult(); if (result2 != null) { result1 = result2; goto label_43; } } result1 = policyBuilder?.Build();
这里如果我们没有设置IAuthorizeData 属性,那么将会使用FallbackPolicy。
同样,我们常说我们有基于角色授权、基于声明授权,基于策略授权,那么其实在源码的概念里面其实就只有基于角色和基于策略,基于声明其实就是一种特殊的策略授权,由官方封装了一下。
那么从这里我们就拿到了AuthorizationPolicy,那么继续在AuthorizationMiddleware 往下看,AuthorizationPolicy 是我们一系列的授权设置,并不是指一个[Authorize],而是指当前访问接口的组合授权的新策略。
里面可能是基于几个角色授权方案,有可能基于几个策略授权方案,那么是否必须通过这些全部的策略方案,还是通过一个即可呢。这两种可能性都有,比如我们要角色是user,而且还要通过积分策略(积分达到一定的标准)。也有可能我们策略是通过user,或者是advanceduser都可以。
int num; if (!awaiter1.IsCompleted) { // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003E1__state = num = 0; TaskAwaiter<AuthorizationPolicy> taskAwaiter = awaiter1; // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003Et__builder.AwaitUnsafeOnCompleted<TaskAwaiter<AuthorizationPolicy>, AuthorizationMiddleware.\u003CInvoke\u003Ed__6>(ref awaiter1, this); return; } policy = awaiter1.GetResult(); TaskAwaiter taskAwaiter1; if (policy == null) { TaskAwaiter awaiter2 = this._next(context).GetAwaiter(); if (!awaiter2.IsCompleted) { // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003E1__state = num = 1; taskAwaiter1 = awaiter2; // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003Et__builder.AwaitUnsafeOnCompleted<TaskAwaiter, AuthorizationMiddleware.\u003CInvoke\u003Ed__6>(ref awaiter2, this); return; } awaiter2.GetResult(); }
这里我们可以看到当我们返回的策略是空的时候,那么直接运行下一个中间件,继续往下看,如果我们设置的授权策略不为空呢。
policyEvaluator = context.RequestServices.GetRequiredService<IPolicyEvaluator>(); TaskAwaiter<AuthenticateResult> awaiter2 = policyEvaluator.AuthenticateAsync(policy, context).GetAwaiter(); if (!awaiter2.IsCompleted) { // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003E1__state = num = 2; TaskAwaiter<AuthenticateResult> taskAwaiter2 = awaiter2; // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003Et__builder.AwaitUnsafeOnCompleted<TaskAwaiter<AuthenticateResult>, AuthorizationMiddleware.\u003CInvoke\u003Ed__6>(ref awaiter2, this); return; } AuthenticateResult result1 = awaiter2.GetResult();
这一块,那么就是我们有我们设置的授权方案里面的认证方案,进行认证一下。
if (endpoint?.Metadata.GetMetadata<IAllowAnonymous>() != null) { TaskAwaiter awaiter3 = this._next(context).GetAwaiter(); if (!awaiter3.IsCompleted) { // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003E1__state = num = 3; taskAwaiter1 = awaiter3; // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003Et__builder.AwaitUnsafeOnCompleted<TaskAwaiter, AuthorizationMiddleware.\u003CInvoke\u003Ed__6>(ref awaiter3, this); return; } awaiter3.GetResult(); } else { bool isEnabled; object resource = !(AppContext.TryGetSwitch("Microsoft.AspNetCore.Authorization.SuppressUseHttpContextAsAuthorizationResource", out isEnabled) & isEnabled) ? (object) context : (object) endpoint; TaskAwaiter<PolicyAuthorizationResult> awaiter3 = policyEvaluator.AuthorizeAsync(policy, result1, context, resource).GetAwaiter(); if (!awaiter3.IsCompleted) { // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003E1__state = num = 4; TaskAwaiter<PolicyAuthorizationResult> taskAwaiter2 = awaiter3; // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003Et__builder.AwaitUnsafeOnCompleted<TaskAwaiter<PolicyAuthorizationResult>, AuthorizationMiddleware.\u003CInvoke\u003Ed__6>(ref awaiter3, this); return; } PolicyAuthorizationResult result2 = awaiter3.GetResult(); TaskAwaiter awaiter4 = context.RequestServices.GetRequiredService<IAuthorizationMiddlewareResultHandler>().HandleAsync(this._next, context, policy, result2).GetAwaiter(); if (!awaiter4.IsCompleted) { // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003E1__state = num = 5; taskAwaiter1 = awaiter4; // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003Et__builder.AwaitUnsafeOnCompleted<TaskAwaiter, AuthorizationMiddleware.\u003CInvoke\u003Ed__6>(ref awaiter4, this); return; } awaiter4.GetResult(); } }
这一块就是如果我们有元数据IAllowAnonymous,那么我们都直接进行下一个中间件即可。
我们的AllowAnonymousAttribute 就继承IAllowAnonymous。
如果没有继承IAllowAnonymous,那么就进行授权处理:TaskAwaiter
TaskAwaiter awaiter4 = context.RequestServices.GetRequiredService
这就是我们看到的授权的抽象过程,为什么是抽象过程呢?这个我们很多看到的都是接口,了解了其流程,但是具体实现细节我们不知道。
那么我们得去看注入服务services.AddAuthorization();。
看之前我们要有我们看的一个目的,上面有的一些疑问是什么是defaultPolicy还有FallbackPolicy确定的规则是什么,这让我们得关心一下IAuthorizationPolicyProvider的具体实现,还有需要知道到底是处理我们认证和授权的,那么得关心一下IPolicyEvaluator和IAuthorizationMiddlewareResultHandler的具体实现。怀抱中这样的目的接着往下看吧。
public static IServiceCollection AddAuthorization( this IServiceCollection services) { if (services == null) throw new ArgumentNullException(nameof (services)); services.AddAuthorizationCore(); services.AddAuthorizationPolicyEvaluator(); return services; }
一下子就能看到core,那么我们知道结尾带core的,那么是这个服务的核心实现了,看下AddAuthorizationCore。
public static IServiceCollection AddAuthorizationCore( this IServiceCollection services) { if (services == null) throw new ArgumentNullException(nameof (services)); services.AddOptions(); services.TryAdd(ServiceDescriptor.Transient<IAuthorizationService, DefaultAuthorizationService>()); services.TryAdd(ServiceDescriptor.Transient<IAuthorizationPolicyProvider, DefaultAuthorizationPolicyProvider>()); services.TryAdd(ServiceDescriptor.Transient<IAuthorizationHandlerProvider, DefaultAuthorizationHandlerProvider>()); services.TryAdd(ServiceDescriptor.Transient<IAuthorizationEvaluator, DefaultAuthorizationEvaluator>()); services.TryAdd(ServiceDescriptor.Transient<IAuthorizationHandlerContextFactory, DefaultAuthorizationHandlerContextFactory>()); services.TryAddEnumerable(ServiceDescriptor.Transient<IAuthorizationHandler, PassThroughAuthorizationHandler>()); return services; }
那么这里我们之间看到了IAuthorizationPolicyProvider。那么这里我们看一下默认策略和Fallback策略是什么。
public Task<AuthorizationPolicy> GetDefaultPolicyAsync() { if (this._cachedDefaultPolicy == null || this._cachedDefaultPolicy.Result != this._options.DefaultPolicy) this._cachedDefaultPolicy = Task.FromResult<AuthorizationPolicy>(this._options.DefaultPolicy); return this._cachedDefaultPolicy; }
这里访问的就是我们的AuthorizationOptions的DefaultPolicy,那么就看一下这个DefaultPolicy是什么。
public AuthorizationPolicy DefaultPolicy { get; set; } = new AuthorizationPolicyBuilder(Array.Empty<string>()).RequireAuthenticatedUser().Build();
那么看一下RequireAuthenticatedUser吧。
public AuthorizationPolicyBuilder RequireAuthenticatedUser() { this.Requirements.Add((IAuthorizationRequirement) new DenyAnonymousAuthorizationRequirement()); return this; }
然后继续看DenyAnonymousAuthorizationRequirement。
public class DenyAnonymousAuthorizationRequirement : AuthorizationHandler<DenyAnonymousAuthorizationRequirement>, IAuthorizationRequirement { protected override Task HandleRequirementAsync( AuthorizationHandlerContext context, DenyAnonymousAuthorizationRequirement requirement) { ClaimsPrincipal user = context.User; if ((user?.Identity == null ? 1 : (!user.Identities.Any<ClaimsIdentity>((Func<ClaimsIdentity, bool>) (i => i.IsAuthenticated)) ? 1 : 0)) == 0) context.Succeed((IAuthorizationRequirement) requirement); return Task.CompletedTask; } public override string ToString() { return "DenyAnonymousAuthorizationRequirement: Requires an authenticated user."; } }
这里面就是检查context.User的一些信息哈,之间检查是否认证成功了。也就是这个授权策略就是认证成功了那么都可以。
那么我们看一下GetFallbackPolicyAsync。
public Task<AuthorizationPolicy?> GetFallbackPolicyAsync() { if (this._cachedFallbackPolicy == null || this._cachedFallbackPolicy.Result != this._options.FallbackPolicy) this._cachedFallbackPolicy = Task.FromResult<AuthorizationPolicy>(this._options.FallbackPolicy); return this._cachedFallbackPolicy; }
那么看下这个FallbackPolicy。
public AuthorizationPolicy? FallbackPolicy { get; set; }
那么这个应该是我们设置的,如果我们不设置,那么就是空的。
那么继续看一下这个AddAuthorizationPolicyEvaluator。
public static IServiceCollection AddAuthorizationPolicyEvaluator( this IServiceCollection services) { if (services == null) throw new ArgumentNullException(nameof (services)); services.TryAddSingleton<AuthorizationPolicyMarkerService>(); services.TryAddTransient<IPolicyEvaluator, PolicyEvaluator>(); services.TryAddTransient<IAuthorizationMiddlewareResultHandler, AuthorizationMiddlewareResultHandler>(); return services; }
里面存在前面需要知道的IPolicyEvaluator 和 IAuthorizationMiddlewareResultHandler。
先看这个PolicyEvaluator,看下如何处理我们授权的。
public virtual async Task<AuthenticateResult> AuthenticateAsync( AuthorizationPolicy policy, HttpContext context) { if (policy.AuthenticationSchemes == null || policy.AuthenticationSchemes.Count <= 0) return context.User?.Identity?.IsAuthenticated.GetValueOrDefault() ? AuthenticateResult.Success(new AuthenticationTicket(context.User, "context.User")) : AuthenticateResult.NoResult(); ClaimsPrincipal newPrincipal = (ClaimsPrincipal) null; foreach (string authenticationScheme in (IEnumerable<string>) policy.AuthenticationSchemes) { AuthenticateResult authenticateResult = await context.AuthenticateAsync(authenticationScheme); if (authenticateResult != null && authenticateResult.Succeeded) newPrincipal = SecurityHelper.MergeUserPrincipal(newPrincipal, authenticateResult.Principal); } if (newPrincipal != null) { context.User = newPrincipal; return AuthenticateResult.Success(new AuthenticationTicket(newPrincipal, string.Join(";", (IEnumerable<string>) policy.AuthenticationSchemes))); } context.User = new ClaimsPrincipal((IIdentity) new ClaimsIdentity()); return AuthenticateResult.NoResult(); }
一段一段看哈。
if (policy.AuthenticationSchemes == null || policy.AuthenticationSchemes.Count <= 0) return context.User?.Identity?.IsAuthenticated.GetValueOrDefault() ? AuthenticateResult.Success(new AuthenticationTicket(context.User, "context.User")) : AuthenticateResult.NoResult();
这一段就是如果我们没有设置AuthenticationSchemes,直接返回context.User是否认证成功了。这里结合上一章来说就是是否默认认证是否成功了。
foreach (string authenticationScheme in (IEnumerable<string>) policy.AuthenticationSchemes) { AuthenticateResult authenticateResult = await context.AuthenticateAsync(authenticationScheme); if (authenticateResult != null && authenticateResult.Succeeded) newPrincipal = SecurityHelper.MergeUserPrincipal(newPrincipal, authenticateResult.Principal); } if (newPrincipal != null) { context.User = newPrincipal; return AuthenticateResult.Success(new AuthenticationTicket(newPrincipal, string.Join(";", (IEnumerable<string>) policy.AuthenticationSchemes))); } context.User = new ClaimsPrincipal((IIdentity) new ClaimsIdentity()); return AuthenticateResult.NoResult();
上面看到的这一段就是只要一个认证策略通过那么就通过了。
那么来看一下授权的处理吧。
public virtual async Task<PolicyAuthorizationResult> AuthorizeAsync( AuthorizationPolicy policy, AuthenticateResult authenticationResult, HttpContext context, object? resource) { if (policy == null) throw new ArgumentNullException(nameof (policy)); AuthorizationResult authorizationResult = await this._authorization.AuthorizeAsync(context.User, resource, policy); return !authorizationResult.Succeeded ? (authenticationResult.Succeeded ? PolicyAuthorizationResult.Forbid(authorizationResult.Failure) : PolicyAuthorizationResult.Challenge()) : PolicyAuthorizationResult.Success(); }
这里是调用了IAuthorizationService的AuthorizeAsync。
那么我看看一下IAuthorizationService的具体实现类DefaultAuthorizationService吧。
public static Task<AuthorizationResult> AuthorizeAsync( this IAuthorizationService service, ClaimsPrincipal user, object? resource, AuthorizationPolicy policy) { if (service == null) throw new ArgumentNullException(nameof (service)); if (policy == null) throw new ArgumentNullException(nameof (policy)); return service.AuthorizeAsync(user, resource, (IEnumerable<IAuthorizationRequirement>) policy.Requirements); }
然后继续看:
public virtual async Task<AuthorizationResult> AuthorizeAsync( ClaimsPrincipal user, object? resource, IEnumerable<IAuthorizationRequirement> requirements) { // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field int num1 = (^this).\u003C\u003E1__state; AuthorizationHandlerContext authContext; AuthorizationResult result; try { if (requirements == null) throw new ArgumentNullException(nameof (requirements)); authContext = this._contextFactory.CreateContext(requirements, user, resource); TaskAwaiter<IEnumerable<IAuthorizationHandler>> awaiter1 = this._handlers.GetHandlersAsync(authContext).GetAwaiter(); if (!awaiter1.IsCompleted) { int num2; // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003E1__state = num2 = 0; TaskAwaiter<IEnumerable<IAuthorizationHandler>> taskAwaiter = awaiter1; // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003Et__builder.AwaitUnsafeOnCompleted<TaskAwaiter<IEnumerable<IAuthorizationHandler>>, DefaultAuthorizationService.\u003CAuthorizeAsync\u003Ed__7>(ref awaiter1, this); return; } IEnumerator<IAuthorizationHandler> enumerator = awaiter1.GetResult().GetEnumerator(); try { while (enumerator.MoveNext()) { TaskAwaiter awaiter2 = enumerator.Current.HandleAsync(authContext).GetAwaiter(); if (!awaiter2.IsCompleted) { // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003E1__state = num1 = 1; TaskAwaiter taskAwaiter = awaiter2; // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003Et__builder.AwaitUnsafeOnCompleted<TaskAwaiter, DefaultAuthorizationService.\u003CAuthorizeAsync\u003Ed__7>(ref awaiter2, this); return; } awaiter2.GetResult(); if (!this._options.InvokeHandlersAfterFailure) { if (authContext.HasFailed) break; } } } finally { if (num1 < 0 && enumerator != null) enumerator.Dispose(); } enumerator = (IEnumerator<IAuthorizationHandler>) null; AuthorizationResult authorizationResult = this._evaluator.Evaluate(authContext); if (authorizationResult.Succeeded) this._logger.UserAuthorizationSucceeded(); else this._logger.UserAuthorizationFailed(authorizationResult.Failure); result = authorizationResult; } catch (Exception ex) { // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003E1__state = -2; authContext = (AuthorizationHandlerContext) null; // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003Et__builder.SetException(ex); return; } // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003E1__state = -2; authContext = (AuthorizationHandlerContext) null; // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003Et__builder.SetResult(result); }
那么还是一段一段看吧。
if (requirements == null) throw new ArgumentNullException(nameof (requirements)); authContext = this._contextFactory.CreateContext(requirements, user, resource); TaskAwaiter<IEnumerable<IAuthorizationHandler>> awaiter1 = this._handlers.GetHandlersAsync(authContext).GetAwaiter();
这一段就是IAuthorizationHandlerProvider 调用GetHandlersAsync 处理AuthorizationHandlerContext 生成IEnumerable
看一下这个AuthorizationHandlerContext。
public Task<IEnumerable<IAuthorizationHandler>> GetHandlersAsync( AuthorizationHandlerContext context) { return Task.FromResult<IEnumerable<IAuthorizationHandler>>(this._handlers); }
然后查看一下这个GetHandlersAsync,其实跟这个AuthorizationHandlerContext 也没啥关系,之所以有这个参数,估计是为了让用户可以覆写这个方法,让用户获取到上下文。
IEnumerator<IAuthorizationHandler> enumerator = awaiter1.GetResult().GetEnumerator(); try { while (enumerator.MoveNext()) { TaskAwaiter awaiter2 = enumerator.Current.HandleAsync(authContext).GetAwaiter(); if (!awaiter2.IsCompleted) { // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003E1__state = num1 = 1; TaskAwaiter taskAwaiter = awaiter2; // ISSUE: explicit reference operation // ISSUE: reference to a compiler-generated field (^this).\u003C\u003Et__builder.AwaitUnsafeOnCompleted<TaskAwaiter, DefaultAuthorizationService.\u003CAuthorizeAsync\u003Ed__7>(ref awaiter2, this); return; } awaiter2.GetResult(); if (!this._options.InvokeHandlersAfterFailure) { if (authContext.HasFailed) break; } } } finally { if (num1 < 0 && enumerator != null) enumerator.Dispose(); }
这一段就是根据IAuthorizationRequirement匹配AuthorizationHandler 进行处理。
public virtual async Task HandleAsync(AuthorizationHandlerContext context) { foreach (TRequirement requirement in context.Requirements.OfType<TRequirement>()) await this.HandleRequirementAsync(context, requirement); }
看一下这个HandleAsync 的具体实现哈,就是通过OfType来处理的,这种方式方便解耦哈。ofType 可以看一下:https://docs.microsoft.com/zh-cn/dotnet/api/system.linq.enumerable.oftype?view=net-6.0。
这上面有一个值得注意的是这个配置:
if (!this._options.InvokeHandlersAfterFailure) { if (authContext.HasFailed) break; }
https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.authorization.authorizationoptions.invokehandlersafterfailure?view=aspnetcore-6.0
这个配置默认是true,也就是说如何我们设置这个为false,只要我们有一个授权处理方案设置HasFailed,那么将会终止。
接着往下看:
enumerator = (IEnumerator<IAuthorizationHandler>) null; AuthorizationResult authorizationResult = this._evaluator.Evaluate(authContext); if (authorizationResult.Succeeded) this._logger.UserAuthorizationSucceeded(); else this._logger.UserAuthorizationFailed(authorizationResult.Failure); result = authorizationResult;
这个就是根据上下文得出授权成功或者失败的结果了,并且会打印log。
Evaluate 看一下哈,授权失败的标准。
public AuthorizationResult Evaluate(AuthorizationHandlerContext context) { return !context.HasSucceeded ? AuthorizationResult.Failed(context.HasFailed ? AuthorizationFailure.ExplicitFail() : AuthorizationFailure.Failed(context.PendingRequirements)) : AuthorizationResult.Success(); }
就是这个HasSucceeded 。
public virtual bool HasSucceeded { get { return !this._failCalled && this._succeedCalled && !this.PendingRequirements.Any<IAuthorizationRequirement>(); } }
所以其实我们的方案是可以进行组合式的,也就是说我们希望多个授权方案只有一个通过,或者多个授权方案都要通过是我们的授权处理具体设计来处理的。
比如说我们成功了就设置_succeedCalled 为true,失败了也不设置_failCalled 为true,这样就只有通过一个即可。
如果我们失败了就设置_failCalled 为true,那么就需要通过全部,看具体设计了,还可以组合多种设计。
那么我们通过返回的结果得出结论AuthorizeAsync的返回结果是:
return !authorizationResult.Succeeded ? (authenticationResult.Succeeded ? PolicyAuthorizationResult.Forbid(authorizationResult.Failure) : PolicyAuthorizationResult.Challenge()) : PolicyAuthorizationResult.Success();
这里可以说明,即使认证不成功,但是只要是授权成功了,就依然是成功的。然后如果授权不成功,那么如果认证失败,返回 PolicyAuthorizationResult.Forbid(authorizationResult.Failure),否则返回PolicyAuthorizationResult.Challenge()。
这里说明netcore 的设计思想是授权不一定要认证成功。
那么我们最后看一下我们对授权的结果是如何进行处理的,IAuthorizationMiddlewareResultHandler的实现类AuthorizationMiddlewareResultHandler。
public async Task HandleAsync( RequestDelegate next, HttpContext context, AuthorizationPolicy policy, PolicyAuthorizationResult authorizeResult) { if (authorizeResult.Challenged) { if (policy.AuthenticationSchemes.Count > 0) { foreach (string authenticationScheme in (IEnumerable<string>) policy.AuthenticationSchemes) await context.ChallengeAsync(authenticationScheme); } else await context.ChallengeAsync(); } else if (authorizeResult.Forbidden) { if (policy.AuthenticationSchemes.Count > 0) { foreach (string authenticationScheme in (IEnumerable<string>) policy.AuthenticationSchemes) await context.ForbidAsync(authenticationScheme); } else await context.ForbidAsync(); } else await next(context); }
如果Challenged和Forbidden,那么会进行相应的处理,如果都没有,那么直接通过进入下一个中间件。
Challenge 是授权失败且认证失败,一般是401,这个看自己怎么处理了。Forbidden是认证成功,但是授权失败,一般是403。
下一节介绍一下endpint,上述为个人整理,如有错误,往请指点。