62 lines
2.6 KiB
C#
62 lines
2.6 KiB
C#
using Abstractions;
|
|
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Http;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.AspNetCore.Mvc.Filters;
|
|
using W542.GandalfReborn.Data.Entities.Security;
|
|
|
|
namespace Security;
|
|
|
|
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
|
|
public class GrAuthorizeAttribute : Attribute, IAuthorizationFilter
|
|
{
|
|
public required string[] Authorities { get; init; }
|
|
public required AuthorityType Type { get; init; }
|
|
public required string ParameterName { get; init; }
|
|
public bool AllRequired { get; init; } = true;
|
|
|
|
public void OnAuthorization(AuthorizationFilterContext context)
|
|
{
|
|
if(IsAnonymousAllowed(context)) return;
|
|
|
|
var invoker = (Invoker)context.HttpContext.User;
|
|
|
|
if (!invoker.IsAuthenticated)
|
|
{
|
|
HandleResponse(context, "One does not simply access this endpoint not authenticated.", StatusCodes.Status401Unauthorized);
|
|
return;
|
|
}
|
|
|
|
var id = context.HttpContext.Request.RouteValues.GetValueOrDefault(ParameterName)?.ToString();
|
|
|
|
if (id is null)
|
|
{
|
|
HandleResponse(context, "One does not simply cause a internal server error.", StatusCodes.Status500InternalServerError);
|
|
return;
|
|
}
|
|
|
|
var missingAuthorities = Type switch
|
|
{
|
|
AuthorityType.Tenant => Authorities.Where(x => !(invoker.TenantAuthorityDictionary.GetValueOrDefault(id)?.Contains(x) ?? false)).ToArray(),
|
|
AuthorityType.App => Authorities.Where(x => !(invoker.AppAuthorityDictionary.GetValueOrDefault(id)?.Contains(x) ?? false)).ToArray(),
|
|
_ => Authorities
|
|
};
|
|
|
|
if (missingAuthorities.Length == 0) return;
|
|
|
|
var typeName = Type == AuthorityType.App ? "app" : "tenant";
|
|
HandleResponse(context, $"One does not simply access this endpoint without {typeName} authorization.", StatusCodes.Status403Forbidden, missingAuthorities);
|
|
}
|
|
|
|
private static void HandleResponse(AuthorizationFilterContext context, string message, int statusCode, string[]? missingAuthorities = null)
|
|
{
|
|
context.Result = missingAuthorities is null
|
|
? new JsonResult(new { StatusCode = statusCode, Message = message }) { StatusCode = statusCode }
|
|
: new JsonResult(new { StatusCode = statusCode, Message = message, MissingAuthorities = missingAuthorities }) { StatusCode = statusCode };
|
|
}
|
|
|
|
private static bool IsAnonymousAllowed(AuthorizationFilterContext context)
|
|
{
|
|
return context.ActionDescriptor.EndpointMetadata.OfType<AllowAnonymousAttribute>().Any();
|
|
}
|
|
} |