昨天基于 ASP.NET Core Policy-based authorization 重構了博文通路授權的代碼,在這篇随筆中記錄一下。建立 Authorization Requirement,配置 Policy,添加 Claim,實作 PermissionEvaluator,調用 IPermissionEvaluator 擷取博文通路授權結果
1昨天基于 ASP.NET Core Policy-based authorization 重構了博文通路授權的代碼,在這篇随筆中記錄一下,ASP.NET Core 中對應的源碼實作見 https://github.com/dotnet/aspnetcore/tree/3.0/src/Security/Authorization 。
建立 Authorization Requirement
實作接口
IAuthorizationRequirement
與抽象類
AuthorizationHandler<T>
,實作類是
AccessPermissionAuthorizationRequirement
。
public class AccessPermissionAuthorizationRequirement :
AuthorizationHandler<AccessPermissionAuthorizationRequirement, AccessPermission>, IAuthorizationRequirement
{
protected override Task HandleRequirementAsync(
AuthorizationHandlerContext context,
AccessPermissionAuthorizationRequirement requirement,
AccessPermission resource)
{
if (context.Resource != null && GetOwnPermission(context).HasFlag(resource))
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
private AccessPermission GetOwnPermission(AuthorizationHandlerContext context)
{
var claim = context.User.Claims.FirstOrDefault(c => c.Type == BlogClaimTypes.AccessPermission);
Enum.TryParse(claim.Value, out AccessPermission permission);
return permission;
}
}
博文通路授權就在這個類中完成的,根據目前通路使用者的 Claims 與博文的通路權限 context.Resource 判斷是否有權限通路目前博文。
配置 Policy
在 Policy 中添加之前的 AccessPermissionAuthorizationRequirement ,在 Startup.ConfigureServices 中添加下面的代碼。
services.AddAuthorization(options => options.AddPolicy(
nameof(AccessPermission),
builder => builder.AddRequirements(new AccessPermissionAuthorizationRequirement())));
添加 Claim
根據目前使用者所擁有的通路權限,添加對應的 Claim ,我們是在一個 middleware 中添加的。
var identity = new ClaimsIdentity();
identity.AddClaim(new Claim(BlogClaimTypes.AccessPermission, accessPermission.ToString()));
context.User.AddIdentity(identity);
實作 PermissionEvaluator
實作 PermissionEvaluator 的目的是簡化調用方的代碼。
IPermissionEvaluator 接口代碼
public interface IPermissionEvaluator
{
Task<PolicyAuthorizationResult> AuthorizeAsync(HttpContext context, AccessPermission permision);
}
PermissionEvaluator 實作代碼
public class PermissionEvaluator : IPermissionEvaluator
{
private readonly IAuthorizationPolicyProvider _policyProvider;
private readonly IPolicyEvaluator _policyEvaluator;
public PermissionEvaluator(
IAuthorizationPolicyProvider policyProvider,
IPolicyEvaluator policyEvaluator)
{
_policyProvider = policyProvider;
_policyEvaluator = policyEvaluator;
}
public async Task<PolicyAuthorizationResult> AuthorizeAsync(HttpContext context, AccessPermission permision)
{
var policy = await _policyProvider.GetPolicyAsync(nameof(AccessPermission));
var authenticateResult = await _policyEvaluator.AuthenticateAsync(policy, context);
var authorizeResult = await _policyEvaluator.AuthorizeAsync(policy, authenticateResult, context, resource: permision);
return authorizeResult;
}
}
調用 IPermissionEvaluator 擷取博文通路授權結果
在 Controller 中注入 IPermissionEvaluator ,在 Action 中添加如下的代碼擷取博文通路授權結果。
var requiredPermission = await _permissionService.DetermineAccessPermission(blogpost);
var authorizationResult = await _permissionEvaluator.AuthorizeAsync(HttpContext, requiredPermission);
if (!authorizationResult.Succeeded)
{
return authorizationResult.Challenged ? Challenge() : Forbid() as IActionResult;
}