Authorization scheme based on NETCORE 1.1

Time:2020-10-28

1、 Preface

Review: initial knowledge of authorization scheme

From the previous section, we have a preliminary understanding and use of the authorization system, asp.net The authorization policy provided by core is a very powerful, rich and flexible authentication and authorization scheme, which can meet most authorization scenarios.

Configure service in configure services: add authorization service to container

public void ConfigureServices(IServiceCollection services)
    {
   	  services.AddAuthorization(options =>
            {
                options.AddPolicy("customizePermisson",
                  policy => policy
                    .Requirements
                    .Add(new PermissionRequirement("user")));
            });
            //In addition, a new handler needs to be registered with the di system within the scope of the iauthorizationhandler type:
            services.AddScoped();
    }

Register pipeline in configure: run to configure HTTP request pipeline using call method

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {    
        //Open authorization
        app.UseAuthorization();

    }

Through the implementation of the above lines of code, you can be authorized. At this time, you can ask, what operations have these lines of code carried out to achieve authorization?

OK, go back to the last part of the last section. In this section, we will uncover the core of the authorization strategy step by step.

2、 Start

Introducing the whole structure

授权

2.1 add authorizationAddAuthorization

Add authorization policy service usageAddAuthorizationMethod to call the.

From the source code, it can be found that after core 3.0, theAuthorizationServiceCollectionExtensions.csIn the file, the originalAddAuthorizationThe method is changed toAddAuthorizationCoreMethods, Microsoft packaged in this piecePolicyServiceCollectionExtensions.csIn the document, theAddAuthorizationThe extension name does not affect the use of previous versions.

Let’s take a look at the aspnetcore source code:

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

            services.AddAuthorizationCore();
            services.AddAuthorizationPolicyEvaluator();
            return services;
        }      
        public static IServiceCollection AddAuthorization(this IServiceCollection services, Action configure)
        {
            if (services == null)
            {
                throw new ArgumentNullException(nameof(services));
            }
            services.AddAuthorizationCore(configure);
            services.AddAuthorizationPolicyEvaluator();
            return services;
        }
    }
public static class AuthorizationServiceCollectionExtensions
    {
        public static IServiceCollection AddAuthorizationCore(this IServiceCollection services)
        {
            if (services == null)
            {
                throw new ArgumentNullException(nameof(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(nameof(services));
            }
            services.Configure(configure);
            return services.AddAuthorizationCore();
        }
    }

As you can see from the above, theAddAuthorizationMethod for authorization configurationAuthorizationOptionsThe method of entrustment is passed on to the reference.

So let’s take a look at the following line of codeAddPolicyImplement the method of adding policy.

options.AddPolicy("customizePermisson",policy => policy.Requirements.Add(new PermissionRequirement("user")));

Check the source code and find that it is a referenceAuthorizationOptionsObject.

2.2 configuration optionsAuthorizationOptions

The authorization option realizes the configuration of addition and authorization, and provides the configuration of authorization service.

The source code is as follows:

public class AuthorizationOptions
    {
        private Dictionary PolicyMap { get; } = new Dictionary(StringComparer.OrdinalIgnoreCase);
      
        public bool InvokeHandlersAfterFailure { get; set; } = true;
      
        public AuthorizationPolicy DefaultPolicy { get; set; } = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
       
        public AuthorizationPolicy? FallbackPolicy { get; set; }

        public void AddPolicy(string name, AuthorizationPolicy policy)
        {
            if (name == null)
            {
                throw new ArgumentNullException(nameof(name));
            }
            if (policy == null)
            {
                throw new ArgumentNullException(nameof(policy));
            }
            PolicyMap[name] = policy;
        }

        public void AddPolicy(string name, Action configurePolicy)
        {
            if (name == null)
            {
                throw new ArgumentNullException(nameof(name));
            }
            if (configurePolicy == null)
            {
                throw new ArgumentNullException(nameof(configurePolicy));
            }
            var policyBuilder = new AuthorizationPolicyBuilder();
            configurePolicy(policyBuilder);
            PolicyMap[name] = policyBuilder.Build();
        }
      
        public AuthorizationPolicy GetPolicy(string name)
        {
            if (name == null)
            {
                throw new ArgumentNullException(nameof(name));
            }
            if (PolicyMap.TryGetValue(name, out var value))
            {
                return value;
            }
            return null;
        }
    }

Define a dictionary

private Dictionary PolicyMap { get; } = new Dictionary(StringComparer.OrdinalIgnoreCase);

The purpose is to save the defined authorization policy in thePolicyMapAnd among themAddPolicyThe method is to add the configured policy to the dictionary.

public void AddPolicy(string name, AuthorizationPolicy policy);
public void AddPolicy(string name, Action configurePolicy);

In this method, two different parameters are involvedAuthorizationPolicyandAuthorizationPolicyBuilder

2.3 authorization strategyAuthorizationPolicy

Represents a collection of authorization requirements and schemes. The specific source code is as follows:

public class AuthorizationPolicy
{
    public AuthorizationPolicy(IEnumerable requirements, IEnumerable authenticationSchemes)
    {
        if (requirements == null)
        {
            throw new ArgumentNullException(nameof(requirements));
        }

        if (authenticationSchemes == null)
        {
            throw new ArgumentNullException(nameof(authenticationSchemes));
        }

        if (requirements.Count() == 0)
        {
            throw new InvalidOperationException(Resources.Exception_AuthorizationPolicyEmpty);
        }
        Requirements = new List(requirements).AsReadOnly();
        AuthenticationSchemes = new List(authenticationSchemes).AsReadOnly();
    }
  
    public IReadOnlyList Requirements { get; }
    
    public IReadOnlyList AuthenticationSchemes { get; }
   
    public static AuthorizationPolicy Combine(params AuthorizationPolicy[] policies)
    {
        if (policies == null)
        {
            throw new ArgumentNullException(nameof(policies));
        }

        return Combine((IEnumerable)policies);
    }
   
    public static AuthorizationPolicy Combine(IEnumerable policies)
    {
        if (policies == null)
        {
            throw new ArgumentNullException(nameof(policies));
        }

        var builder = new AuthorizationPolicyBuilder();
        foreach (var policy in policies)
        {
            builder.Combine(policy);
        }
        return builder.Build();
    }
   
    public static async Task CombineAsync(IAuthorizationPolicyProvider policyProvider, IEnumerable authorizeData)
    {
        if (policyProvider == null)
        {
            throw new ArgumentNullException(nameof(policyProvider));
        }

        if (authorizeData == null)
        {
            throw new ArgumentNullException(nameof(authorizeData));
        }

        // Avoid allocating enumerator if the data is known to be empty
        var skipEnumeratingData = false;
        if (authorizeData is IList dataList)
        {
            skipEnumeratingData = dataList.Count == 0;
        }

        AuthorizationPolicyBuilder policyBuilder = null;
        if (!skipEnumeratingData)
        {
            foreach (var authorizeDatum in authorizeData)
            {
                if (policyBuilder == null)
                {
                    policyBuilder = new AuthorizationPolicyBuilder();
                }

                var useDefaultPolicy = true;
                if (!string.IsNullOrWhiteSpace(authorizeDatum.Policy))
                {
                    var policy = await policyProvider.GetPolicyAsync(authorizeDatum.Policy);
                    if (policy == null)
                    {
                        throw new InvalidOperationException(Resources.FormatException_AuthorizationPolicyNotFound(authorizeDatum.Policy));
                    }
                    policyBuilder.Combine(policy);
                    useDefaultPolicy = false;
                }

                var rolesSplit = authorizeDatum.Roles?.Split(',');
                if (rolesSplit != null && rolesSplit.Any())
                {
                    var trimmedRolesSplit = rolesSplit.Where(r => !string.IsNullOrWhiteSpace(r)).Select(r => r.Trim());
                    policyBuilder.RequireRole(trimmedRolesSplit);
                    useDefaultPolicy = false;
                }

                var authTypesSplit = authorizeDatum.AuthenticationSchemes?.Split(',');
                if (authTypesSplit != null && authTypesSplit.Any())
                {
                    foreach (var authType in authTypesSplit)
                    {
                        if (!string.IsNullOrWhiteSpace(authType))
                        {
                            policyBuilder.AuthenticationSchemes.Add(authType.Trim());
                        }
                    }
                }

                if (useDefaultPolicy)
                {
                    policyBuilder.Combine(await policyProvider.GetDefaultPolicyAsync());
                }
            }
        }

        // If we have no policy by now, use the fallback policy if we have one
        if (policyBuilder == null)
        {
            var fallbackPolicy = await policyProvider.GetFallbackPolicyAsync();
            if (fallbackPolicy != null)
            {
                return fallbackPolicy;
            }
        }

        return policyBuilder?.Build();
    }
}

We can see from the source code,AuthorizationobjectCombineMethod is used to merge the authorization policies and call theAuthorizationPolicyBuilderObjectCombineMethods to merge authorization schemes or authorization policies. Let’s have a lookAuthorizationPolicyObjectCombineAsyncMethod, the parameters here are usedIAuthorizeDataAt the same time, the process of this method is to merge the role-based, scheme based or policy based methods into the authorization policy mode, which is also calledAuthorizationPolicyBuilderObject to implement the merge. So you can see thatAuthorizationPolicyBuilderProvides some creationAuthorizationPolicyMethods.

At this time, we can find that, in fact, the role-based and scheme based authorization methods mentioned before are essentially based on policy authorization.

2.4 construction strategyAuthorizationPolicyBuilder

Except for the use mentioned aboveAuthorizationPolicyIn addition to objects, we can also useAuthorizationPolicyBuilderObject toBuiderTo createAuthorizationPolicyObject, set multipleAuthorizationPolicyThe array provided by theAuthorizationPolicyBuilderProvidedCombineMethod is used forAuthorizationPolicyAuthorization building provides many convenient ways.

public class AuthorizationPolicyBuilder
{ 
    public AuthorizationPolicyBuilder(params string[] authenticationSchemes)
    {
        AddAuthenticationSchemes(authenticationSchemes);
    }
    public AuthorizationPolicyBuilder(AuthorizationPolicy policy)
    {
        Combine(policy);
    }
    public IList Requirements { get; set; } = new List();    
    public IList AuthenticationSchemes { get; set; } = new List();
    public AuthorizationPolicyBuilder AddAuthenticationSchemes(params string[] schemes)
    {
        foreach (var authType in schemes)
        {
            AuthenticationSchemes.Add(authType);
        }
        return this;
    }    
    public AuthorizationPolicyBuilder AddRequirements(params IAuthorizationRequirement[] requirements)
    {
        foreach (var req in requirements)
        {
            Requirements.Add(req);
        }
        return this;
    }
    public AuthorizationPolicyBuilder Combine(AuthorizationPolicy policy)
    {
        if (policy == null)
        {
            throw new ArgumentNullException(nameof(policy));
        }

        AddAuthenticationSchemes(policy.AuthenticationSchemes.ToArray());
        AddRequirements(policy.Requirements.ToArray());
        return this;
    }    
    public AuthorizationPolicyBuilder RequireClaim(string claimType, params string[] allowedValues)
    {
        if (claimType == null)
        {
            throw new ArgumentNullException(nameof(claimType));
        }

        return RequireClaim(claimType, (IEnumerable)allowedValues);
    } 
    public AuthorizationPolicyBuilder RequireClaim(string claimType, IEnumerable allowedValues)
    {
        if (claimType == null)
        {
            throw new ArgumentNullException(nameof(claimType));
        }

        Requirements.Add(new ClaimsAuthorizationRequirement(claimType, allowedValues));
        return this;
    }    
    public AuthorizationPolicyBuilder RequireClaim(string claimType)
    {
        if (claimType == null)
        {
            throw new ArgumentNullException(nameof(claimType));
        }

        Requirements.Add(new ClaimsAuthorizationRequirement(claimType, allowedValues: null));
        return this;
    }     
    public AuthorizationPolicyBuilder RequireRole(params string[] roles)
    {
        if (roles == null)
        {
            throw new ArgumentNullException(nameof(roles));
        }

        return RequireRole((IEnumerable)roles);
    }  
    public AuthorizationPolicyBuilder RequireRole(IEnumerable roles)
    {
        if (roles == null)
        {
            throw new ArgumentNullException(nameof(roles));
        }

        Requirements.Add(new RolesAuthorizationRequirement(roles));
        return this;
    }    
    public AuthorizationPolicyBuilder RequireUserName(string userName)
    {
        if (userName == null)
        {
            throw new ArgumentNullException(nameof(userName));
        }

        Requirements.Add(new NameAuthorizationRequirement(userName));
        return this;
    }
    public AuthorizationPolicyBuilder RequireAuthenticatedUser()
    {
        Requirements.Add(new DenyAnonymousAuthorizationRequirement());
        return this;
    }
    public AuthorizationPolicyBuilder RequireAssertion(Func handler)
    {
        if (handler == null)
        {
            throw new ArgumentNullException(nameof(handler));
        }

        Requirements.Add(new AssertionRequirement(handler));
        return this;
    }
    public AuthorizationPolicyBuilder RequireAssertion(Func> handler)
    {
        if (handler == null)
        {
            throw new ArgumentNullException(nameof(handler));
        }

        Requirements.Add(new AssertionRequirement(handler));
        return this;
    } 
    public AuthorizationPolicy Build()
    {
        return new AuthorizationPolicy(Requirements, AuthenticationSchemes.Distinct());
    }
}

More from aboveIAuthorizationRequirementObjects can be discovered, authorization requirementsRequirementAttributes are the core scheme of the policy, each of whichRequirementBoth represent a way of authorization. meanwhileIAuthorizationPolicyBuilderCreate their corresponding usage for these predefined scenarios and add them to theRequirementsSet.

2.5 authorization requirementsIAuthorizationRequirement

public interface IAuthorizationRequirement
   {
   }

The interface has no implementation members, because authorization requirements have different representations, so there is no specific implementation member. The purpose of authorization requirements is to verify whether a current user has corresponding requirementsIAuthorizationRequirementThe implementation classes of the interface are inheritedIAuthorizationHandlerInterface to provide the handleasync method to implement the corresponding authorization verification.

Here’s how it works asp.net Several default implementations in core frameworkIAuthorizationRequirementImplementation type.

2.5.1 DenyAnonymousAuthorizationRequirement

To prevent anonymous users from operating, the implication is to deny unauthorized anonymous users access to resources.

The source code is as follows:

public class DenyAnonymousAuthorizationRequirement : AuthorizationHandler, IAuthorizationRequirement
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, DenyAnonymousAuthorizationRequirement requirement)
    {
        var user = context.User;
        var userIsAnonymous =
            user?.Identity == null ||
            !user.Identities.Any(i => i.IsAuthenticated);
        if (!userIsAnonymous)
        {
            context.Succeed(requirement);
        }
        return Task.CompletedTask;
    }
}

Through the user’sCliamPrincipalWhether the object identity is empty or an authenticated user identity is used to determine whether the current requested user is from an anonymous user.

2.5.2 NameAuthorizationRequirement

Specify the authorization method of the user name, and determine whether the current user matches a specified user to authorize access to resources.

The source code is as follows:

public class NameAuthorizationRequirement : AuthorizationHandler, IAuthorizationRequirement
{
    public NameAuthorizationRequirement(string requiredName)
    {
        if (requiredName == null)
        {
            throw new ArgumentNullException(nameof(requiredName));
        }

        RequiredName = requiredName;
    }
    public string RequiredName { get; }
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, NameAuthorizationRequirement requirement)
    {
        if (context.User != null)
        {
            if (context.User.Identities.Any(i => string.Equals(i.Name, requirement.RequiredName)))
            {
                context.Succeed(requirement);
            }
        }
        return Task.CompletedTask;
    }
}

amongRequiredNameAttribute is the authorized user, and theHandleRequirementAsyncMethod to verify the current user’sClaimPrincipalThe identity of the object andRequiredNameWhether there is a match.

The judgment here is based on string.Equals () indicates that the user names compared here are case sensitive.

2.5.3 ClaimsAuthorizationRequirement

Based on the authorization policy of the specified claim type, verify whether the current user declares the type and candidate value.

The source code is as follows:

public class ClaimsAuthorizationRequirement : AuthorizationHandler, IAuthorizationRequirement
    {
        public ClaimsAuthorizationRequirement(string claimType, IEnumerable allowedValues)
        {
            if (claimType == null)
            {
                throw new ArgumentNullException(nameof(claimType));
            }
            ClaimType = claimType;
            AllowedValues = allowedValues;
        }
        public string ClaimType { get; }
        public IEnumerable AllowedValues { get; }
        protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, ClaimsAuthorizationRequirement requirement)
        {
            if (context.User != null)
            {
                var found = false;
                if (requirement.AllowedValues == null || !requirement.AllowedValues.Any())
                {
                    found = context.User.Claims.Any(c => string.Equals(c.Type, requirement.ClaimType, StringComparison.OrdinalIgnoreCase));
                }
                else
                {
                    found = context.User.Claims.Any(c => string.Equals(c.Type, requirement.ClaimType, StringComparison.OrdinalIgnoreCase)
                                                        && requirement.AllowedValues.Contains(c.Value, StringComparer.Ordinal));
                }
                if (found)
                {
                    context.Succeed(requirement);
                }
            }
            return Task.CompletedTask;
        }
    }

As we can see from the above,ClaimTypeandAllowedValuesThese two properties are initialized in the constructor to represent the declared type of the current declaration and the default allowable value, respectively. adoptHandleRequirementAsyncTo authorize the inspection.

2.5.4 RolesAuthorizationRequirement

The role-based authorization policy checks whether the current user has a role that matches the contract. If so, he can access the corresponding resources.

The source code is as follows:

public class RolesAuthorizationRequirement : AuthorizationHandler, IAuthorizationRequirement
{
    public RolesAuthorizationRequirement(IEnumerable allowedRoles)
    {
        if (allowedRoles == null)
        {
            throw new ArgumentNullException(nameof(allowedRoles));
        }

        if (allowedRoles.Count() == 0)
        {
            throw new InvalidOperationException(Resources.Exception_RoleRequirementEmpty);
        }
        AllowedRoles = allowedRoles;
    }
    public IEnumerable AllowedRoles { get; }
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, RolesAuthorizationRequirement requirement)
    {
        if (context.User != null)
        {
            bool found = false;
            if (requirement.AllowedRoles == null || !requirement.AllowedRoles.Any())
            {
                // Review: What do we want to do here?  No roles requested is auto success?
            }
            else
            {
                found = requirement.AllowedRoles.Any(r => context.User.IsInRole(r));
            }
            if (found)
            {
                context.Succeed(requirement);
            }
        }
        return Task.CompletedTask;
    }
}

amongAllowedRolesRepresents a collection of target role lists. adoptHandleRequirementAsyncTo implement authorization verification, callIsInRoleMethod to determine the current user’sClaimsPrincipalWhether the object has a specified role.

2.5.5 AssertionRequirement

be based onAuthorizationHandlerContextTo declare authorization in the form of a context assertion.

The source code is as follows:

public class AssertionRequirement : IAuthorizationHandler, IAuthorizationRequirement
{
    public Func> Handler { get; }
    public AssertionRequirement(Func handler)
    {
        if (handler == null)
        {
            throw new ArgumentNullException(nameof(handler));
        }

        Handler = context => Task.FromResult(handler(context));
    }
    public AssertionRequirement(Func> handler)
    {
        if (handler == null)
        {
            throw new ArgumentNullException(nameof(handler));
        }

        Handler = handler;
    }
    public async Task HandleAsync(AuthorizationHandlerContext context)
    {
        if (await Handler(context))
        {
            context.Succeed(this);
        }
    }
}

Pass type isFunc>To represent the assertion and use it to authorize validation. stayHandleAsyncIn the inspection method, the delegate object is called directly to complete the judgment.

2.5.6 OperationAuthorizationRequirement

Authorization policy based on predefined actions.

The source code is as follows:

public class OperationAuthorizationRequirement : IAuthorizationRequirement
{
    public string Name { get; set; }
}

It can be seen from the above that it only contains an operation nameNameProperty to map the authorized target object to a predefined operation.

3、 Use cases

EmergingIAuthorizationRequirementObjects can be discovered, authorization requirementsRequirementAttribute is the core scheme of the policy, each in theRequirementBoth represent a way of authorization.

In the above, we adopted the construction strategyAuthorizationPolicyBuilderThe object’s source code can be found, providing us with multiple methods by predefinedIAuthorizationRequirementType to create and add it to theRequirementsSet.

3.1 application

The instance application is as follows: Configure Service in configure services

public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();

            var combindPolicy = new AuthorizationPolicyBuilder().RequireClaim("role").Build();
            services.AddAuthorization(options =>
            {
                //DenyAnonymousAuthorizationRequirement
                options.AddPolicy("DenyAnonyUser", policy => policy.RequireAuthenticatedUser());
                //NameAuthorizationRequirement
                options.AddPolicy ("NameAuth", policy =>  policy.RequireUserName (AI Sanyuan);
                //ClaimsAuthorizationRequirement
                options.AddPolicy("ClaimsAuth", policy => policy.RequireClaim("role","admin"));
                //RolesAuthorizationRequirement
                options.AddPolicy("RolesAuth", policy => policy.RequireRole("admin","user"));
                //AssertionRequirement
                options.AddPolicy("AssertAuth", policy => policy.RequireAssertion(c=>c.User.HasClaim(o=>o.Type=="role")));
                //Similarly, you can directly call the combine method and the policy authoritationpolicy
                options.AddPolicy("CombindAuth", policy => policy.Combine(combindPolicy));
            });
}

Above, we implement several default implementations in the frameworkIAuthorizationRequirementThe application of implementation type in practice can be realized through different authorization requirements. At the same time, the above methods can be combined into an object for calling.

3.2 expansion

Of course, in addition to these default implementations, we can also customize themRequirementTo meet our needs.

When I first learned about authorization in the last section, I already mentioned the part of custom authorization, so I’ll see it again here.

Define a permission policyPermissionRequirementThis policy also contains some properties.

public class PermissionRequirement: IAuthorizationRequirement
{
    public string _permissionName { get; }

    public PermissionRequirement(string PermissionName)
    {
        _permissionName = PermissionName;
    }
}

Define a policy processing class again

public class PermissionRequirementHandler : AuthorizationHandler
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement)
    {
        var role = context.User.FindFirst(c => c.Type == ClaimTypes.Role);
        if (role != null)
        {
            var roleValue = role.Value;
            if (roleValue==requirement._permissionName)
            {
                context.Succeed(requirement);
            }
        }
        return Task.CompletedTask;

Configuration use

public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers();
        //Authorization based on custom policy
        services.AddAuthorization(options =>
        {
            options.AddPolicy("customizePermisson",
              policy => policy
                .Requirements
                .Add(new PermissionRequirement("admin")));
        });
        //In addition, a new handler needs to be registered with the di system within the scope of the iauthorizationhandler type:
        services.AddScoped();
        //As mentioned earlier, the requirement can contain multiple handlers. If more than one handler is registered with the di system for the same request of the authorization layer, one success is sufficient.
    }

Special instructions

The handler used above is a one-to-one relationship. When the declaration requirements meet the conditions, the task authorization is successful. After the authorization is successful, the task is authorized successfully,context.SucceedWill be called by meeting the requirements as its only parameter.

However, authorization policies also contain one to many requirements, which belong to&Only if all of them are verified, can the final authorization succeed. However, in some scenarios, we may hope that an authorization policy can be applied to many situations. For example, when we enter the company, we need to show the employee card before we can be authorized to enter. However, if we forget to bring the employee card, we can apply for a temporary card, and the authorization can be successful.

Here is an official document

public class BuildingEntryRequirement : IAuthorizationRequirement
{
}
public class BadgeEntryHandler : AuthorizationHandler
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
                                                   BuildingEntryRequirement requirement)
    {
        if (context.User.HasClaim(c => c.Type == "BadgeId" &&
                                       c.Issuer == "http://microsoftsecurity"))
        {
            context.Succeed(requirement);
        }

        //TODO: Use the following if targeting a version of
        //.NET Framework older than 4.6:
        //      return Task.FromResult(0);
        return Task.CompletedTask;
    }
}
public class TemporaryStickerHandler : AuthorizationHandler
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, 
                                                   BuildingEntryRequirement requirement)
    {
        if (context.User.HasClaim(c => c.Type == "TemporaryBadgeId" &&
                                       c.Issuer == "https://microsoftsecurity"))
        {
            // We'd also check the expiration date on the sticker.
            context.Succeed(requirement);
        }

        //TODO: Use the following if targeting a version of
        //.NET Framework older than 4.6:
        //      return Task.FromResult(0);
        return Task.CompletedTask;
    }
}

We have defined two handlers, but if we want them to be executed, we need to register them in the di system

services.AddSingleton();
services.AddSingleton();

Make sure both handlers are registered. If a handler is used after a policy evaluationcontext.succeed()To successfully build an entry requirement, the policy evaluation will succeed. But when we callcontext.Fail()Method will fail to set the authorization structure. In that case, the final result will be authorization failure. So normally. We all just set up tagscontext.succeed()

4、 Description

Here are some of the declaration methods in the source code above.

4.1 IAuthorizeData

Use the iauthorizedate interface method. Define the data set required for authorization rules to be applied to resources.

public interface IAuthorizeData
{
    string Policy { get; set; }
    string Roles { get; set; }
    string AuthenticationSchemes { get; set; }
}

Policy: gets or sets the policy name that determines access to the resource.

Roles: gets or sets a comma separated list of roles that are allowed to access resources.

AuthenticationSchemes: gets or sets a comma separated list of scenarios from which user information can be constructed.

thereforeIAuthorizeDataAs defined inpolicyrolesAuthenticationSchemesThe three represent three authorization methods in the authorization system.

The specific use will be described in detail in the implementation process of authorization.

5、 Follow up

The above mainly explains the source code of authorization in terms of configuration. Originally, it was intended to continue to write, but considering that the overall length may be too long, it is not easy to read.

So that’s all for the first part of authorization disclosure. In the following articles, we will continue to understand the mystery of the internal mechanism of authorization and how to implement the authorization process.

6、 Summary

  1. From the beginning of adding authorization configuration, we introduce the required authorization configuration options, and different authorization requirements build different policy methods, so as to achieve a satisfied authorization requirement configuration.
  2. If there is something wrong or incomprehensible, I hope you can point out more, ask questions, discuss together, keep learning and make progress together.
  3. Reference documents and official source code