using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using TakeoutSaaS.Application.Identity.Abstractions; using TakeoutSaaS.Application.Identity.Contracts; using TakeoutSaaS.Module.Authorization.Attributes; using TakeoutSaaS.Shared.Abstractions.Constants; using TakeoutSaaS.Shared.Abstractions.Results; using TakeoutSaaS.Shared.Web.Api; using TakeoutSaaS.Shared.Web.Security; namespace TakeoutSaaS.AdminApi.Controllers; /// /// 管理后台认证接口 /// /// 提供登录、刷新 Token 以及用户权限查询能力。 /// 认证服务 [ApiVersion("1.0")] [Authorize] [Route("api/admin/v{version:apiVersion}/auth")] public sealed class AuthController(IAdminAuthService authService) : BaseApiController { /// /// 登录获取 Token /// /// 登录请求。 /// 取消标记。 /// 包含访问令牌与刷新令牌的响应。 [HttpPost("login")] [AllowAnonymous] [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)] public async Task> Login([FromBody] AdminLoginRequest request, CancellationToken cancellationToken) { var response = await authService.LoginAsync(request, cancellationToken); return ApiResponse.Ok(response); } /// /// 刷新 Token /// /// 刷新令牌请求。 /// 取消标记。 /// 新的访问令牌与刷新令牌。 [HttpPost("refresh")] [AllowAnonymous] [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)] public async Task> RefreshToken([FromBody] RefreshTokenRequest request, CancellationToken cancellationToken) { var response = await authService.RefreshTokenAsync(request, cancellationToken); return ApiResponse.Ok(response); } /// /// 获取当前用户信息 /// /// /// 示例: /// /// GET /api/admin/v1/auth/profile /// Header: Authorization: Bearer <JWT> /// 响应: /// { /// "success": true, /// "code": 200, /// "message": "操作成功", /// "data": { /// "userId": "900123456789012345", /// "account": "admin@tenant1", /// "displayName": "租户管理员", /// "tenantId": "100000000000000001", /// "merchantId": null, /// "roles": ["TenantAdmin"], /// "permissions": ["identity:permission:read", "merchant:read", "order:read"], /// "avatar": "https://cdn.example.com/avatar.png" /// } /// } /// /// /// 取消标记。 /// 当前用户档案信息。 [HttpGet("profile")] [PermissionAuthorize("identity:profile:read")] [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)] [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status401Unauthorized)] public async Task> GetProfile(CancellationToken cancellationToken) { // 1. 从 JWT 中获取当前用户标识 var userId = User.GetUserId(); if (userId == 0) { return ApiResponse.Error(ErrorCodes.Unauthorized, "Token 缺少有效的用户标识"); } // 2. 读取用户档案并返回 var profile = await authService.GetProfileAsync(userId, cancellationToken); return ApiResponse.Ok(profile); } /// /// 查询指定用户的角色与权限概览(当前租户范围)。 /// /// /// 示例: /// /// GET /api/admin/v1/auth/permissions/900123456789012346 /// Header: Authorization: Bearer <JWT> /// 响应: /// { /// "success": true, /// "code": 200, /// "data": { /// "userId": "900123456789012346", /// "tenantId": "100000000000000001", /// "merchantId": "200000000000000001", /// "account": "ops.manager", /// "displayName": "运营经理", /// "roles": ["OpsManager", "Reporter"], /// "permissions": ["delivery:read", "order:read", "payment:read"], /// "createdAt": "2025-12-01T08:30:00Z" /// } /// } /// /// /// 目标用户 ID。 /// 取消标记。 /// 用户权限概览,未找到则返回 404。 [HttpGet("permissions/{userId:long}")] [PermissionAuthorize("identity:permission:read")] [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)] [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status404NotFound)] public async Task> GetUserPermissions(long userId, CancellationToken cancellationToken) { var result = await authService.GetUserPermissionsAsync(userId, cancellationToken); return result is null ? ApiResponse.Error(ErrorCodes.NotFound, "用户不存在或不属于当前租户") : ApiResponse.Ok(result); } }