Providing a Permission Check Endpoint in the 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();
}
Remote Permission Checker
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;
Reimplementing the Permission Handler
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();
}
}
Invalidating the Cache for Testing
await distributedCache.SetObjectAsync(cacheKey, new PermissionGrantCacheItem(isGranted), new DistributedCacheEntryOptions
{
AbsoluteExpiration = DateTimeOffset.Now
});
Readability Refactoring
Regenerate the demo data and rename Name in authorization to PermissionName, which is more readable.
Resource Descriptor Refactoring
public record struct ResourceInfo(string ResourceType, string ResourceId) : IAuthorizationResource
{
public override readonly string ToString() => $"{ResourceType}:{ResourceId}";
}