Reorganize the practice of. net core -- reading the source code of authority middleware [46]

preface

The authentication middleware was introduced earlier. Let's take a look at the authorization middleware.

text

app.UseAuthorization();

Authorization middleware is this. We mentioned earlier that authentication middleware will not stop the whole middleware.

Authentication middleware has two functions. If our authentication scheme implements IAuthenticationRequestHandler, it will call HandleRequestAsync to judge whether to continue running.

Then we set the default authentication scheme, and the specific processing of the authentication scheme will be called. If the authentication is successful, context.User will be given.

However, in this authentication middleware, if the authentication fails, it will continue to run, because we have other methods that can be accessed without authentication, so the middleware cannot be killed with a stick.

The main function of this authentication middleware is that if the user can pass the default authentication scheme, he will be labeled with a label, which is context.User.

context.user is the public abstract claimsprincipal user {get; set;}, which contains some user information. Authentication middleware does this. Let's see what authorization middleware does.

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;
}

There is an IAuthorizationPolicyProvider, which is used to manage the management of authorization policies. As expected, it should be the addition, deletion, modification and query of authorization policies.

  public interface IAuthorizationPolicyProvider
  {
    Task<AuthorizationPolicy?> GetPolicyAsync(string policyName);

    Task<AuthorizationPolicy> GetDefaultPolicyAsync();

    Task<AuthorizationPolicy?> GetFallbackPolicyAsync();
  }

Well, there are only queries and no additions. Let's see. The additions should be made elsewhere.

After checking the source code in front of us, we found that the end of the provider means to provide, xxProvoder, which is what it provides for us, so there must be something like get in it.

Maybe there are additions, deletions and changes in xxProvoder, but it's not necessarily. Depending on the design complexity, if the design is more complex, the additions, deletions and changes will be placed in another place. This is the design to another place. It's relatively complex.

Let's take a look at 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();
}

One paragraph at a time.

  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();

In this paragraph, we can see that it is mainly to obtain our authorization strategy.

First, through endpoint = context.GetEndpoint(); Get our routing destination.

I wonder how much you know about Endpoint? I'll sort it out and introduce it later, mainly app.UseRouting(); And app.UseEndpoints(); To introduce these two things, we only need to know some of our routing information and attribute characteristics loaded by Endpoint.

endpoint1.Metadata.GetOrderedMetadata() gets metadata about IAuthorizeData. I don't know how much you know about metadata. Here, we can understand it as attribute data.

Metadata( Metadata),Also known as intermediary data and relay data, it is the data describing the data( data about data),It mainly describes data attributes( property)Metadata is a kind of electronic catalog. In order to achieve the purpose of compiling the catalog, we must describe and collect the content or characteristics of the data, so as to assist in data retrieval. Dublin Core Set( Dublin Core Metadata Initiative,DCMI)Is an application of metadata, which was developed by the International Library Computer Center in February 1995( OCLC)National Supercomputing Application Center( National Center for Supercomputing Applications,NCSA)The co sponsored seminar invited 52 librarians and computer experts to jointly formulate specifications and create a set of characteristics describing electronic documents on the network.

Here is to get our attribute, get our IAuthorizeData attribute, see if this thing is particularly familiar?

  [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; }
  }

Yes, it will get the permission scheme we configured.

OK, let's take a look at authorizationpolicy. Combinesync.

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);
}

It's really a little long to post first, but we only look at the normal authorization part, and we don't look at the others.

  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;

This paragraph is to make some logical judgments to judge whether we have configured the authorization policy.

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;
}

This paragraph is about how to handle if we configure authorization policies. Ha, each authorization policy will be processed through 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;
  }

This is to find out the authorization scheme of the policy pattern and store it in the authorization policy builder.

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;
  }

Here is to find out the role-based authorization and put it into the authorization policy builder.

  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());
	}
  }

This is to find out the authentication method, and then add it to the authentication schemes of the authorization policy builder.

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;
  }

Here, if we do not specify our authorization method, the default authorization verification method will be used.

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();

If the IAuthorizeData property is not set here, FallbackPolicy will be used.

Similarly, we often say that we have role-based authorization, declaration based authorization and policy based authorization. In fact, in the concept of source code, there are only role-based and policy based authorization. Declaration based authorization is actually a special policy authorization, which is encapsulated by the official.

Then we get the authorization policy from here. Then, continue to look at the authorization middleware. The authorization policy is a series of authorization settings, not a [Authorize], but a new policy for the combined authorization of the current access interface.

It may be based on several role authorization schemes, or it may be based on several policy authorization schemes. Do you have to pass all of these policy schemes, or one of them? Both possibilities exist. For example, we want the role to be user, and we also need to pass the integration strategy (the score reaches a certain standard) It's also possible that our strategy can be through user or advanced user.

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();
}

Here we can see that when the returned policy is empty, run the next middleware directly and continue to look down. What if the authorization policy we set is not empty.

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();

For this part, we have the authentication scheme in the authorization scheme we set up to authenticate.

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();
  }
}

In this part, if we have metadata IAllowAnonymous, we can all go directly to the next middleware.

Our AllowAnonymousAttribute inherits IAllowAnonymous.

If IAllowAnonymous is not inherited, authorization processing will be performed: taskawaiter awater3 = policyevaluator. Authorizeasync (policy, result1, context, resource). Getawaiter();

Taskawaiter awater4 = context. Requestservices. Getrequiredservice(). Handleasync (this. _next, context, policy, result2). Getawaiter();. This handles the authorization result.

This is the abstract process of authorization. Why is it an abstract process? Many of us see interfaces and understand their processes, but we don't know the specific implementation details.

Then we have to look at the injection service services.AddAuthorization();.

Before we look at it, we need to have a purpose. Some of the questions above are what is the defaultPolicy and what are the rules determined by FallbackPolicy. This makes us care about the specific implementation of IAuthorizationPolicyProvider, and we need to know exactly how to handle our authentication and authorization, Then, we should pay attention to the specific implementation of IPolicyEvaluator and iauthorizationmiddlewareresulthhandler. For this purpose in your arms, look down.

public static IServiceCollection AddAuthorization(
  this IServiceCollection services)
{
  if (services == null)
	throw new ArgumentNullException(nameof (services));
  services.AddAuthorizationCore();
  services.AddAuthorizationPolicyEvaluator();
  return services;
}

You can see the core at once. Then we know that the core with core at the end is the core implementation of the service. Take a look at the 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;
}

Here we see the IAuthorizationPolicyProvider. So let's take a look at the default policy and Fallback policy.

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;
}

The DefaultPolicy of our AuthorizationOptions is accessed here. Let's see what the DefaultPolicy is.

public AuthorizationPolicy DefaultPolicy { get; set; } = new AuthorizationPolicyBuilder(Array.Empty<string>()).RequireAuthenticatedUser().Build();

Then take a look at RequireAuthenticatedUser.

public AuthorizationPolicyBuilder RequireAuthenticatedUser()
{
  this.Requirements.Add((IAuthorizationRequirement) new DenyAnonymousAuthorizationRequirement());
  return this;
}

Then continue to look at denyA anonymous authorization requirement.

  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.";
    }
  }

This is to check some information of context.User, and check whether the authentication is successful. That is, if the authorization policy is successful, it can be used.

Let's take a look at 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;
}

Then take a look at this fallback policy.

public AuthorizationPolicy? FallbackPolicy { get; set; }

This should be set by us. If we don't set it, it will be empty.

Then continue to look at the add authorization policy evaluator.

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;
}

There are IPolicyEvaluator and IAuthorizationMiddlewareResultHandler that you need to know earlier.

Let's take a look at the policy evaluator and see how to handle our authorization.

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();
}

One by one.

if (policy.AuthenticationSchemes == null || policy.AuthenticationSchemes.Count <= 0)
        return context.User?.Identity?.IsAuthenticated.GetValueOrDefault() ? AuthenticateResult.Success(new AuthenticationTicket(context.User, "context.User")) : AuthenticateResult.NoResult();

In this paragraph, if we do not set AuthenticationSchemes, we will directly return whether context.User authentication is successful. Combined with the previous chapter, it is whether the default authentication is successful.

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();

The above paragraph is that as long as an authentication policy passes, it passes.

Let's take a look at authorization processing.

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();
}

Here is the AuthorizeAsync that called IAuthorizationService.

Let me take a look at the specific implementation class DefaultAuthorizationService of IAuthorizationService.

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);
}

Then continue to look:

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);
}

Well, let's look at it paragraph by paragraph.

if (requirements == null)
  throw new ArgumentNullException(nameof (requirements));
authContext = this._contextFactory.CreateContext(requirements, user, resource);
TaskAwaiter<IEnumerable<IAuthorizationHandler>> awaiter1 = this._handlers.GetHandlersAsync(authContext).GetAwaiter();

In this section, IAuthorizationHandlerProvider calls GetHandlersAsync to process the AuthorizationHandlerContext to generate IEnumerable.

Take a look at the AuthorizationHandlerContext.

public Task<IEnumerable<IAuthorizationHandler>> GetHandlersAsync(
  AuthorizationHandlerContext context)
{
  return Task.FromResult<IEnumerable<IAuthorizationHandler>>(this._handlers);
}

Then check the GetHandlersAsync. In fact, it has nothing to do with the AuthorizationHandlerContext. It is estimated that this parameter is used to allow users to override this method and get the context.

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();
}

This section is processed by matching the authorization handler according to the IAuthorizationRequirement.

public virtual async Task HandleAsync(AuthorizationHandlerContext context)
{
  foreach (TRequirement requirement in context.Requirements.OfType<TRequirement>())
	await this.HandleRequirementAsync(context, requirement);
}

Let's take a look at the specific implementation of HandleAsync, which is handled through ofType. This method is convenient for decoupling. ofType: https://docs.microsoft.com/zh-cn/dotnet/api/system.linq.enumerable.oftype?view=net-6.0.

It is worth noting that this configuration:

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

This configuration defaults to true, that is, how to set this to false. As long as we have an authorization processing scheme to set hasfiled, it will terminate.

Then look down:

enumerator = (IEnumerator<IAuthorizationHandler>) null;
AuthorizationResult authorizationResult = this._evaluator.Evaluate(authContext);
if (authorizationResult.Succeeded)
  this._logger.UserAuthorizationSucceeded();
else
  this._logger.UserAuthorizationFailed(authorizationResult.Failure);
result = authorizationResult;

This is the result of successful or failed authorization according to the context, and the log will be printed.

Evaluate, take a look at the criteria for authorization failure.

public AuthorizationResult Evaluate(AuthorizationHandlerContext context)
{
  return !context.HasSucceeded ? AuthorizationResult.Failed(context.HasFailed ? AuthorizationFailure.ExplicitFail() : AuthorizationFailure.Failed(context.PendingRequirements)) : AuthorizationResult.Success();
}

This is HasSucceeded.

public virtual bool HasSucceeded
{
  get
  {
	return !this._failCalled && this._succeedCalled && !this.PendingRequirements.Any<IAuthorizationRequirement>();
  }
}

Therefore, in fact, our scheme can be combined, that is, we want only one of multiple authorization schemes to pass, or multiple authorization schemes to be processed through our specific authorization processing design.

For example, if we succeed, we can set it_ succeedCalled is true. If it fails, it will not be set_ failCalled is true, so only one can be passed.

If we fail, set_ If failCalled is true, you need to go through all, depending on the specific design, and you can combine multiple designs.

Then we conclude from the returned results that the returned results of AuthorizeAsync are:

return !authorizationResult.Succeeded ? (authenticationResult.Succeeded ? PolicyAuthorizationResult.Forbid(authorizationResult.Failure) : PolicyAuthorizationResult.Challenge()) : PolicyAuthorizationResult.Success();

It can be explained here that even if the authentication is unsuccessful, as long as the authorization is successful, it is still successful. Then, if the authorization is unsuccessful, if the authentication fails, return policyauthorizationresult. Forbidden (authorizationresult. Failure), otherwise return PolicyAuthorizationResult.Challenge().

This shows that the design idea of netcore is that authorization does not have to be successful.

Finally, let's take a look at how we handle the authorization results. The implementation class of IAuthorizationMiddlewareResultHandler is 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);
}

If Challenged and Forbidden, the corresponding processing will be carried out. If none, the next middleware will be entered directly through.

The Challenge refers to authorization failure and authentication failure, usually 401. It depends on how you deal with it. Forbidden means that the authentication is successful, but the authorization fails. It is generally 403.

junction

The next section introduces endpin. The above is personal sorting. If there is any error, please give advice.

Added by mutedgirl on Sun, 28 Nov 2021 13:41:09 +0200