基于资源授权的最佳实践
在 Identity Service 中提供权限检查接口
[HttpHead]
public async Task<IActionResult> CheckPermission(string permissionName, string? resourceType = null, string? resourceId = null
{
if (await permissionChecker.IsGrantedAsync(permissionName, resourceType, resourceId))
{
return Ok();
}
return Forbid();
}
远程权限检查器
Dictionary<string, string?> parameters = new()
{
[nameof(name)] = name,
[nameof(resourceType)] = resourceType,
[nameof(resourceId)] = resourceId
};
string queryString = QueryHelpers.AddQueryString(string.Empty, parameters);
HttpRequestMessage request = new(HttpMethod.Head, queryString);
using HttpResponseMessage response = await httpClient.SendAsync(request);
return response.IsSuccessStatusCode;
重新实现权限处理程序
public class PermissionRequirementHandler(IPermissionChecker permissionChecker) : AuthorizationHandler<OperationAuthorizationRequirement>
{
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, OperationAuthorizationRequirement requirement)
{
if (context.Resource is IAuthorizationResource resource)
{
if (await permissionChecker.IsGrantedAsync(context.User, requirement.Name, resource.ResourceType, resource.ResourceId))
{
context.Succeed(requirement);
}
else
{
context.Fail();
}
return;
}
if (await permissionChecker.IsGrantedAsync(context.User, requirement.Name))
{
context.Succeed(requirement);
return;
}
context.Fail();
}
}
取消缓存以便测试
await distributedCache.SetObjectAsync(cacheKey, new PermissionGrantCacheItem(isGranted), new DistributedCacheEntryOptions
{
AbsoluteExpiration = DateTimeOffset.Now
});
可读性重构
重新生成演示数据,并将授权中的 Name 改为 PermissionName,具有更强的可读性。
资源描述重构
public record struct ResourceInfo(string ResourceType, string ResourceId) : IAuthorizationResource
{
public override readonly string ToString() => $"{ResourceType}:{ResourceId}";
}