基於 ASP.NET Core Policy-based authorization 實現博文訪問授權
阿新 • • 發佈:2020-06-27
昨天基於 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>, IAuthorizationRequirement { protected override Task HandleRequirementAsync( AuthorizationHandlerContext context, AccessPermissionAuthorizationRequirement requirement) { if (context.Resource != null && GetOwnPermission(context).HasFlag((AccessPermission)context.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;
}