50 lines
1.9 KiB
C#
50 lines
1.9 KiB
C#
using MiaoJiZhang.Domain.Entities;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.AspNetCore.Mvc.Filters;
|
|
|
|
namespace MiaoJiZhang.Api.Services;
|
|
|
|
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
|
|
public sealed class AdminAuthAttribute(params string[] roles) : Attribute, IAsyncAuthorizationFilter
|
|
{
|
|
public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
|
|
{
|
|
var request = context.HttpContext.Request;
|
|
var service = context.HttpContext.RequestServices.GetRequiredService<AdminSessionService>();
|
|
var authenticated = await service.AuthenticateAsync(
|
|
context.HttpContext,
|
|
validateCsrf: !AdminSessionService.IsSafeMethod(request.Method),
|
|
context.HttpContext.RequestAborted);
|
|
if (authenticated is null)
|
|
{
|
|
context.Result = new UnauthorizedObjectResult(new
|
|
{
|
|
error = "admin_session_required",
|
|
message = "管理会话已失效,请重新登录",
|
|
});
|
|
return;
|
|
}
|
|
|
|
var principal = authenticated.Value.Principal;
|
|
if (principal.MustChangePassword &&
|
|
!request.Path.StartsWithSegments("/api/admin/auth"))
|
|
{
|
|
context.Result = new ObjectResult(new
|
|
{
|
|
error = "password_change_required",
|
|
message = "首次登录必须修改密码",
|
|
}) { StatusCode = StatusCodes.Status403Forbidden };
|
|
return;
|
|
}
|
|
if (principal.Role == AdminRoles.Viewer &&
|
|
!AdminSessionService.IsSafeMethod(request.Method) &&
|
|
!request.Path.StartsWithSegments("/api/admin/auth"))
|
|
{
|
|
context.Result = new ForbidResult();
|
|
return;
|
|
}
|
|
if (roles.Length > 0 && !roles.Contains(principal.Role))
|
|
context.Result = new ForbidResult();
|
|
}
|
|
}
|