138 lines
5.5 KiB
C#
138 lines
5.5 KiB
C#
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;
|
|
/// <summary>
|
|
/// 管理后台认证接口
|
|
/// </summary>
|
|
/// <remarks>提供登录、刷新 Token 以及用户权限查询能力。</remarks>
|
|
/// <param name="authService">认证服务</param>
|
|
[ApiVersion("1.0")]
|
|
[Authorize]
|
|
[Route("api/admin/v{version:apiVersion}/auth")]
|
|
public sealed class AuthController(IAdminAuthService authService) : BaseApiController
|
|
{
|
|
/// <summary>
|
|
/// 登录获取 Token
|
|
/// </summary>
|
|
/// <param name="request">登录请求。</param>
|
|
/// <param name="cancellationToken">取消标记。</param>
|
|
/// <returns>包含访问令牌与刷新令牌的响应。</returns>
|
|
[HttpPost("login")]
|
|
[AllowAnonymous]
|
|
[ProducesResponseType(typeof(ApiResponse<TokenResponse>), StatusCodes.Status200OK)]
|
|
public async Task<ApiResponse<TokenResponse>> Login([FromBody] AdminLoginRequest request, CancellationToken cancellationToken)
|
|
{
|
|
var response = await authService.LoginAsync(request, cancellationToken);
|
|
return ApiResponse<TokenResponse>.Ok(response);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 刷新 Token
|
|
/// </summary>
|
|
/// <param name="request">刷新令牌请求。</param>
|
|
/// <param name="cancellationToken">取消标记。</param>
|
|
/// <returns>新的访问令牌与刷新令牌。</returns>
|
|
[HttpPost("refresh")]
|
|
[AllowAnonymous]
|
|
[ProducesResponseType(typeof(ApiResponse<TokenResponse>), StatusCodes.Status200OK)]
|
|
public async Task<ApiResponse<TokenResponse>> RefreshToken([FromBody] RefreshTokenRequest request, CancellationToken cancellationToken)
|
|
{
|
|
var response = await authService.RefreshTokenAsync(request, cancellationToken);
|
|
return ApiResponse<TokenResponse>.Ok(response);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取当前用户信息
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// 示例:
|
|
/// <code>
|
|
/// 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"
|
|
/// }
|
|
/// }
|
|
/// </code>
|
|
/// </remarks>
|
|
/// <param name="cancellationToken">取消标记。</param>
|
|
/// <returns>当前用户档案信息。</returns>
|
|
[HttpGet("profile")]
|
|
[PermissionAuthorize("identity:profile:read")]
|
|
[ProducesResponseType(typeof(ApiResponse<CurrentUserProfile>), StatusCodes.Status200OK)]
|
|
[ProducesResponseType(typeof(ApiResponse<CurrentUserProfile>), StatusCodes.Status401Unauthorized)]
|
|
public async Task<ApiResponse<CurrentUserProfile>> GetProfile(CancellationToken cancellationToken)
|
|
{
|
|
// 1. 从 JWT 中获取当前用户标识
|
|
var userId = User.GetUserId();
|
|
if (userId == 0)
|
|
{
|
|
return ApiResponse<CurrentUserProfile>.Error(ErrorCodes.Unauthorized, "Token 缺少有效的用户标识");
|
|
}
|
|
|
|
// 2. 读取用户档案并返回
|
|
var profile = await authService.GetProfileAsync(userId, cancellationToken);
|
|
return ApiResponse<CurrentUserProfile>.Ok(profile);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 查询指定用户的角色与权限概览(当前租户范围)。
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// 示例:
|
|
/// <code>
|
|
/// 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"
|
|
/// }
|
|
/// }
|
|
/// </code>
|
|
/// </remarks>
|
|
/// <param name="userId">目标用户 ID。</param>
|
|
/// <param name="cancellationToken">取消标记。</param>
|
|
/// <returns>用户权限概览,未找到则返回 404。</returns>
|
|
[HttpGet("permissions/{userId:long}")]
|
|
[PermissionAuthorize("identity:permission:read")]
|
|
[ProducesResponseType(typeof(ApiResponse<UserPermissionDto>), StatusCodes.Status200OK)]
|
|
[ProducesResponseType(typeof(ApiResponse<UserPermissionDto>), StatusCodes.Status404NotFound)]
|
|
public async Task<ApiResponse<UserPermissionDto>> GetUserPermissions(long userId, CancellationToken cancellationToken)
|
|
{
|
|
var result = await authService.GetUserPermissionsAsync(userId, cancellationToken);
|
|
return result is null
|
|
? ApiResponse<UserPermissionDto>.Error(ErrorCodes.NotFound, "用户不存在或不属于当前租户")
|
|
: ApiResponse<UserPermissionDto>.Ok(result);
|
|
}
|
|
}
|