72 lines
2.4 KiB
C#
72 lines
2.4 KiB
C#
using DysonNetwork.Shared.Proto;
|
|
using Grpc.Core;
|
|
using Microsoft.AspNetCore.Http;
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
namespace DysonNetwork.Shared.Auth;
|
|
|
|
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
|
|
public class AskPermissionAttribute(string key, PermissionNodeActorType type = PermissionNodeActorType.Account)
|
|
: Attribute
|
|
{
|
|
public string Key { get; } = key;
|
|
public PermissionNodeActorType Type { get; } = type;
|
|
}
|
|
|
|
public class RemotePermissionMiddleware(RequestDelegate next)
|
|
{
|
|
public async Task InvokeAsync(HttpContext httpContext, PermissionService.PermissionServiceClient permissionService,
|
|
ILogger<RemotePermissionMiddleware> logger)
|
|
{
|
|
var endpoint = httpContext.GetEndpoint();
|
|
|
|
var attr = endpoint?.Metadata
|
|
.OfType<AskPermissionAttribute>()
|
|
.FirstOrDefault();
|
|
|
|
if (attr != null)
|
|
{
|
|
if (httpContext.Items["CurrentUser"] is not Account currentUser)
|
|
{
|
|
httpContext.Response.StatusCode = StatusCodes.Status403Forbidden;
|
|
await httpContext.Response.WriteAsync("Unauthorized");
|
|
return;
|
|
}
|
|
|
|
// Superuser will bypass all the permission check
|
|
if (currentUser.IsSuperuser)
|
|
{
|
|
await next(httpContext);
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
var permResp = await permissionService.HasPermissionAsync(new HasPermissionRequest
|
|
{
|
|
Actor = currentUser.Id,
|
|
Key = attr.Key
|
|
});
|
|
|
|
if (!permResp.HasPermission)
|
|
{
|
|
httpContext.Response.StatusCode = StatusCodes.Status403Forbidden;
|
|
await httpContext.Response.WriteAsync($"Permission {attr.Key} was required.");
|
|
return;
|
|
}
|
|
}
|
|
catch (RpcException ex)
|
|
{
|
|
logger.LogError(ex,
|
|
"gRPC call to PermissionService failed while checking permission {Key} for actor {Actor}", attr.Key,
|
|
currentUser.Id
|
|
);
|
|
httpContext.Response.StatusCode = StatusCodes.Status500InternalServerError;
|
|
await httpContext.Response.WriteAsync("Error checking permissions.");
|
|
return;
|
|
}
|
|
}
|
|
|
|
await next(httpContext);
|
|
}
|
|
} |