为 Blazor 授权动态添加策略声明

Posted

技术标签:

【中文标题】为 Blazor 授权动态添加策略声明【英文标题】:Dynamically adding policy claims for Blazor authorization 【发布时间】:2021-12-27 11:15:38 【问题描述】:

我正在为内部授权创建一个身份验证和授权处理程序。我的目的是让我的同事可以轻松地将解决方案实施到他们自己的项目中。我们使用 Azure AD 进行身份验证,我们使用 Azure 组进行授权。为了做到这一点,我觉得我一直在弄清楚如何以有效的方式添加授权策略。

现在我正在通过官方描述的方式在 Blazor webassembly 托管配置中的客户端项目的 Program 类中添加它:

            builder.Services.AddAuthorizationCore(options =>
                options.AddPolicy("PolicyName", policy =>
                
                    policy.RequireClaim("ClaimType", "ClaimValue");
                )
            );

这很好用,但不直观,因为任何给定的项目都可能需要几种不同的策略

我还添加了一个自定义授权策略提供程序,如 Microsoft 的此文档中所述:

https://docs.microsoft.com/en-us/aspnet/core/security/authorization/iauthorizationpolicyprovider?view=aspnetcore-6.0

根据他们对本文档的描述,尤其是文档中的前几行,我认为这就是我要寻找的内容。但如果不手动添加每个策略,我似乎仍然无法让它按预期工作。

如果需要,我可以展示我的授权策略提供程序的自定义实现,但它与 Github 中的文档几乎完全相同。

【问题讨论】:

【参考方案1】:

策略最常在应用程序启动时在StartupConfigureServices 方法中注册。

public void ConfigureServices(IServiceCollection services)    

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

政策IsDeveloper 要求用户拥有IsDeveloper 的声明,其值为true

您可以通过Authorize 属性应用策略的角色。

[Route("api/[controller]")]
[ApiController]
public class SystemController 

    [Authorize(Policy = “IsDeveloper”)]
    public IActionResult LoadDebugInfo()
    
        // ...
    

Blazors 指令和组件也适用于策略。

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

更轻松的管理

使用基于角色的身份验证,如果我们有几个角色可以访问受保护的资源 - 比如说 adminmoderator。我们需要去他们被允许访问的每个区域并添加一个Authorize 属性。

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

一开始这似乎并不算太​​糟糕,但是如果出现新要求并且第三个角色superuser 需要相同的访问权限怎么办?我们现在需要遍历每个区域并更新所有角色。使用基于策略的身份验证,我们可以避免这种情况。

我们可以在一个地方定义一个策略,然后将它一次应用于所有需要它的资源。然后,当需要添加额外的角色时,我们可以从中心点更新策略,而无需更新各个资源。

 public void ConfigureServices(IServiceCollection services)

    services.AddAuthorization(config =>
    
    config.AddPolicy("IsAdmin", policy => policy.RequireRole("admin", "moderator", "superuser"));
    );

[Authorize(Policy = "IsAdmin")]

创建共享策略

我们需要从 NuGet 安装 Microsoft.AspNetCore.Authorization 包才能执行此操作。

之后,使用以下代码创建一个名为 Policies 的新类。

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


这里我们使用AuthorizationPolicyBuilder 来定义每个策略,两者都要求用户经过身份验证,然后是Admin 角色或User 角色,具体取决于策略。

配置服务器

Startup 类中注册ConfigureServices 中的策略。在对AddAuthentication的现有调用下添加以下代码。

services.AddAuthorization(config =>

    config.AddPolicy(Policies.IsAdmin, Policies.IsAdminPolicy());
    config.AddPolicy(Policies.IsUser, Policies.IsUserPolicy());
);

注册每个策略并使用我们在Policies 类中定义的常量来声明它们的名称,这样可以使用魔术字符串来保存。

如果我们转移到SampleDataController,我们可以更新Authorize 属性以使用新的IsAdmin 策略而不是旧角色。

[Authorize(Policy = Policies.IsAdmin)]
[Route("api/[controller]")]
public class SampleDataController : Controller

同样,我们可以使用我们的名称常量来避免魔法字符串。

配置客户端

我们的服务器现在正在使用我们定义的新策略,剩下要做的就是交换我们的 Blazor 客户端以也使用它们。

与服务器一样,我们将首先在 ConfigureServices 中注册 Startup 类中的策略。我们已经接到了AddAuthorizationCore 的电话,所以我们只需要更新它。

services.AddAuthorizationCore(config =>

    config.AddPolicy(Policies.IsAdmin, Policies.IsAdminPolicy());
    config.AddPolicy(Policies.IsUser, Policies.IsUserPolicy());
);

Index.razor 中,更新 AuthorizeView 组件以使用策略 - 仍然避免使用魔法字符串。

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

最后,更新FetchData.razors Authorize 属性。

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

参考here

【讨论】:

以上是关于为 Blazor 授权动态添加策略声明的主要内容,如果未能解决你的问题,请参考以下文章

在 Blazor 中引用动态创建的控件

在 Blazor 中配置基于策略的授权

Blazor WebAssembly .Net 5 Msal 身份验证中基于角色的授权

ASP.NET Core 5 授权策略未检测到声明

如何使用基于策略的授权将所需的声明附加到令牌?

为一个类动态的添加属性