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(); 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(); } }