我正在创建一个用于内部授权目的的身份验证和授权处理程序。我的目的是让我的同事可以轻松地将解决方案实施到他们自己的项目中。我们使用 Azure AD 进行身份验证,使用Azure 组进行授权。为了做到这一点,我觉得我一直在弄清楚如何以有效的方式添加授权策略。
现在,我正在通过官方描述的方式在 Blazor Web 程序集托管配置中的客户端项目的 Program 类中添加它:
builder.Services.AddAuthorizationCore(options =>
options.AddPolicy("PolicyName", policy =>
{
policy.RequireClaim("ClaimType", "ClaimValue");
})
);
这工作正常,但它并不直观,因为任何给定的项目都可能需要几个不同的策略。
我还添加了一个自定义授权策略提供程序,如 Microsoft 中的本文档中所述:
https://learn.microsoft.com/en-us/aspnet/core/security/authorization/iauthorizationpolicyprovider?view=aspnetcore-6.0
我认为这将是我正在寻找的,基于他们对本文档的描述,尤其是文档中的前几行。但是,如果不手动添加每个策略,我似乎仍然无法使其按预期工作。
如果需要,我可以显示授权策略提供程序的自定义实现,但它几乎与文档的 Github 中看到的完全一样。
策略最常在应用程序启动时在Startup
类ConfigureServices
方法中注册。
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthorization(config =>
{
config.AddPolicy("IsDeveloper", policy => policy.RequireClaim("IsDeveloper","true"));
});
}
策略IsDeveloper
要求用户具有值为true
的声明IsDeveloper
。
角色 您可以通过Authorize
属性应用策略。
[Route("api/[controller]")]
[ApiController]
public class SystemController
{
[Authorize(Policy = “IsDeveloper”)]
public IActionResult LoadDebugInfo()
{
// ...
}
}
开拓者指令和组件也适用于策略。
@page "/debug"
@attribute [Authorize(Policy = "IsDeveloper")]
< AuthorizeView Policy="IsDeveloper">
< p>You can only see this if you satisfy the IsDeveloper policy.< /p>
< /AuthorizeView>
更轻松的管理
使用基于角色的身份验证,如果我们有几个角色可以访问受保护的资源 - 假设admin
和moderator
。我们需要访问允许他们访问的每个区域并添加一个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 客户端以使用它们。
与服务器一样,我们将首先在Startup
类中注册ConfigureServices
中的策略。我们已经接到了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.razor
Authorize
属性。
@attribute [Authorize(Policy = Policies.IsAdmin)]
参考这里