[Translation] configuration is based on the authorization Blazor policy WebAssembly (Blazor client) application

Original: https: //chrissainty.com/securing-your-blazor-apps-configuring-policy-based-authorization-with-blazor/

In the previous article , I showed how to add role-based to Blazor WebAssembly (Blazor client) application authorization. In this article, I'll show you how to use Blazor configure policy-based authorization.

Policy-based authorization

ASP.NET Core allows a more flexible way to create an authorization rule policy-based authorization. Policy authorization concept consists of three components:

  • Policy - Policy have one or more requirements.
  • Requirement - Strategies for assessing the parameters of the current user principal data collection.
  • Handler  - processing program used to determine whether the current user has access to subject the requested resource.

Strategy is usually when the application starts Startupthe class ConfigureServiceregistration process.

            services.AddAuthorization(config => {
                config.AddPolicy("IsDeveloper", policy => policy.RequireClaim("IsDeveloper", "true"));
            });

In the above example, the policy IsDeveloperrequires the user needs to have IsDevelopera statement, and a value true.

Like the role authorization, you can use the same Authorizeattributes apply to policy authorization.

[Route("api/[controller]")]
[ApiController]
public class SystemController 
{
    [Authorize(Policy = “IsDeveloper”)]
    public IActionResult LoadDebugInfo()
    {
        // ...
    }
}

Blazors instructions and components also can use the same strategy.

@page "/debug"
@attribute [Authorize(Policy = "IsDeveloper")]
<AuthorizeView Policy="IsDeveloper">
    <p>You can only see this if you satisfy the IsDeveloper policy.</p>
</AuthorizeView>

Easier to manage

The biggest advantage of policy-based authorization is to improve authorization management applications. Use role-based authorization, if we have two roles are allowed to access protected resources - such as adminand moderator. We need to add a resource each is allowed access to the Authorizeproperty.

[Authorize(Roles = "admin,moderator")]

It does not look bad at the beginning, but if a new need arises, third role superuser, need the same access rights, how to do it? Now we need to update all of the roles in each access resource. Through policy-based verification, we can avoid this situation.

We can define a policy in one, and then apply it to all the resources it needs. When the need to add additional roles, we only need to update this policy, without the need to update each resource.

public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthorization(config =>
    {
    config.AddPolicy("IsAdmin", policy => policy.RequireRole("admin", "moderator", "superuser"));
    });
}
[Authorize(Policy = "IsAdmin")]

Create custom requirements

Policy authorization is very flexible, you can create role-based requirements, statements, and even create custom requirements. Let's look at how to create custom requirements.

Normally, when you have a complex logic, we use a custom needs. As mentioned above, we need a demand and a top handler to use policy authorization.

Let's create a check the user's e-mail address is whether demand for the company domain. We need to create an authorization demand class, this class needs to implement IAuthorizationRequirementthe interface, it's just an empty marker interface.

public class CompanyDomainRequirement : IAuthorizationRequirement
{
    public string CompanyDomain { get; }

    public CompanyDomainRequirement(string companyDomain)
    {
        CompanyDomain = companyDomain;
    }
}

Next, we need to create a class that inherits from the demand for our AuthorizationHandlerhandler, Tis to deal with the demand.

public class CompanyDomainHandler : AuthorizationHandler<CompanyDomainRequirement>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, CompanyDomainRequirement requirement)
    {
        if (!context.User.HasClaim(c => c.Type == ClaimTypes.Email))
        {
            return Task.CompletedTask;
        }
        
        var emailAddress = context.User.FindFirst(c => c.Type == ClaimTypes.Email).Value;
        
        if (emailAddress.EndsWith(requirement.CompanyDomain))
        {
            return context.Succeed(requirement);
        }
        
        return Task.CompletedTask;
    }
}

In the above code, we check for e-mail statement. If so, we check whether it ends in the domain specified as required, and if so, success is returned, otherwise it fails.

We just want our demands a strategy associated with it, and CompanyDomainHandlerregistered with the dependency injection container.

public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthorization(config =>
    {
        config.AddPolicy("IsCompanyUser", policy =>
            policy.Requirements.Add(new CompanyDomainRequirement("newco.com")));
    });

    services.AddSingleton<IAuthorizationHandler, CompanyDomainHandler>();
}

For more detailed information about the custom requirements, we recommend checking out the official documentation .

Blazor use policy

Now that we understand what the strategy is, let's see how to use them in your application.

In Blazor application on an article we will switch to a policy-based authorization. As part of this effort, we will see another advantage of policy-based authorization, that can define policies in a shared project and reference them in the server and the client.

Create a Sharing Policy

In share the project before you create a policy, we need to start NuGet install Microsoft.AspNetCore.Authorizationthis package.

After installation, use the following code to create a named Policies class.

    public static class Policies
    {
        public const string IsAdmin = "IsAdmin";
        public const string IsUser = "IsUser";

        public static AuthorizationPolicy IsAdminPolicy() {
            return new AuthorizationPolicyBuilder().RequireAuthenticatedUser()
                .RequireRole("Admin")
                .Build();
        }

        public static AuthorizationPolicy IsUserPolicy() {
            return new AuthorizationPolicyBuilder().RequireAuthenticatedUser()
                .RequireRole("User")
                .Build();
        }
    }

We first define the two constants IsAdminand IsUser. We will use them when enrollment policy. Next is the strategy itself, IsAdminPolicyand IsUserPolicy. Here I use AuthorizationPolicyBuilderto define each policy, the two policies require users to authenticate, and then depending on the policy, users may be Adminroles and Userroles.

Configure the server

Now that we have defined the policy, we need to let the server to use them. First, Startupclass ConfigureServicesenrollment policy method, AddAuthenticationafter adding the following code.

            services.AddAuthorization(config => {
                config.AddPolicy(Policies.IsAdmin, Policies.IsAdminPolicy());
                config.AddPolicy(Policies.IsUser, Policies.IsUserPolicy());
            });

The code is very easy to understand, we use Policiesthe constants defined in the class to declare their names and register each policy, avoid using magic string.

In WeatherForecastControlleryou can useIsAdmin策略代旧的角色。

    [ApiController]
    [Route("[controller]")]
    [Authorize(Policy = Policies.IsAdmin)]
    public class WeatherForecastController : ControllerBase

Similarly, we can use the name to avoid the constant magic string.

Configuring the Client

The server can now use our new strategy defined, the next step is to use them in Blazor client.

And the service side, we are in the Startupclass ConfigureServicesenrollment policy approach. We have previously called AddAuthorizationCore, so only need to update it.

            services.AddAuthorizationCore(config => {
                config.AddPolicy(Policies.IsAdmin, Policies.IsAdminPolicy());
                config.AddPolicy(Policies.IsUser, Policies.IsUserPolicy());
            });

In Index.razoruse policy update AuthorizeViewcomponents - as to avoid the use of magic string.

<AuthorizeView Policy="@Policies.IsUser">
    <p>You can only see this if you satisfy the IsUser policy.</p>
</AuthorizeView>

<AuthorizeView Policy="@Policies.IsAdmin">
    <p>You can only see this if you satisfy the IsAdmin policy.</p>
</AuthorizeView>

Finally, update FetchData.razorthe Authorizeproperty.

@attribute [Authorize(Policy = Policies.IsAdmin)]

That's it! Our application is now transferred to policy-based authorization. We now have a more flexible licensing system, you can use roles, statements, policy or custom combination of any of the above.

About server Blazor

I did not specifically discuss the server Blazor, the reason is very simple, can be done without problems on our transfer to the server Blazor.

to sum up

In this article, we discuss the ASP.NET Core and Blazor policy-based authorization. We also understand some of the advantages of using role-based authorization with respect to the policy-based authorization and we will migrate applications from a role-based authentication to verify policy-based.

Finally Code ( GitHub )

Guess you like

Origin www.cnblogs.com/chen8854/p/securing-your-blazor-apps-configuring-policy-based-authorization-with-blazor.html