refactor(authentication): Update authorization schemes to use "Bearer" for consistency
- Changed authorization schemes in AuthController, RolesController, and UsersController from JwtBearerDefaults.AuthenticationScheme to "Bearer" for uniformity across the application. - Added new endpoints in UsersController to retrieve user roles and permissions by user ID, enhancing user management capabilities.
This commit is contained in:
@@ -86,7 +86,7 @@ public class AuthController : ControllerBase
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
/// <returns>Result of password change operation</returns>
|
||||
[HttpPost("change-password")]
|
||||
[Microsoft.AspNetCore.Authorization.Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
|
||||
[Microsoft.AspNetCore.Authorization.Authorize(AuthenticationSchemes = "Bearer")]
|
||||
[SwaggerOperation(
|
||||
Summary = "Change password",
|
||||
Description = "Changes the password for the currently authenticated user. Requires current password verification.",
|
||||
@@ -125,7 +125,7 @@ public class AuthController : ControllerBase
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
/// <returns>Result of logout operation</returns>
|
||||
[HttpPost("logout")]
|
||||
[Microsoft.AspNetCore.Authorization.Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
|
||||
[Microsoft.AspNetCore.Authorization.Authorize(AuthenticationSchemes = "Bearer")]
|
||||
[SwaggerOperation(
|
||||
Summary = "Logout",
|
||||
Description = "Logs out the current user and revokes all associated tokens.",
|
||||
@@ -219,7 +219,7 @@ public class AuthController : ControllerBase
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
/// <returns>QR code and recovery codes</returns>
|
||||
[HttpPost("2fa/enable")]
|
||||
[Microsoft.AspNetCore.Authorization.Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
|
||||
[Microsoft.AspNetCore.Authorization.Authorize(AuthenticationSchemes = "Bearer")]
|
||||
[SwaggerOperation(
|
||||
Summary = "Enable 2FA",
|
||||
Description = "Initiates 2FA setup. Returns QR code and recovery codes. Must be verified with /2fa/verify.",
|
||||
@@ -264,7 +264,7 @@ public class AuthController : ControllerBase
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
/// <returns>Result of 2FA verification</returns>
|
||||
[HttpPost("2fa/verify")]
|
||||
[Microsoft.AspNetCore.Authorization.Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
|
||||
[Microsoft.AspNetCore.Authorization.Authorize(AuthenticationSchemes = "Bearer")]
|
||||
[SwaggerOperation(
|
||||
Summary = "Verify 2FA code",
|
||||
Description = "Verifies the TOTP code and completes 2FA setup.",
|
||||
@@ -304,7 +304,7 @@ public class AuthController : ControllerBase
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
/// <returns>Result of disabling 2FA</returns>
|
||||
[HttpPost("2fa/disable")]
|
||||
[Microsoft.AspNetCore.Authorization.Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
|
||||
[Microsoft.AspNetCore.Authorization.Authorize(AuthenticationSchemes = "Bearer")]
|
||||
[SwaggerOperation(
|
||||
Summary = "Disable 2FA",
|
||||
Description = "Disables 2FA for the current user. Requires verification with current 2FA code.",
|
||||
@@ -438,7 +438,7 @@ public class AuthController : ControllerBase
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
/// <returns>List of linked providers</returns>
|
||||
[HttpGet("linked-accounts")]
|
||||
[Microsoft.AspNetCore.Authorization.Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
|
||||
[Microsoft.AspNetCore.Authorization.Authorize(AuthenticationSchemes = "Bearer")]
|
||||
[SwaggerOperation(
|
||||
Summary = "Get linked accounts",
|
||||
Description = "Returns list of external OAuth providers linked to current user's account.",
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace IamService.API.Controllers;
|
||||
[ApiController]
|
||||
[ApiVersion("1.0")]
|
||||
[Route("api/v{version:apiVersion}/roles")]
|
||||
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
|
||||
[Authorize(AuthenticationSchemes = "Bearer")]
|
||||
[SwaggerTag("Role management endpoints - requires authentication")]
|
||||
public class RolesController : ControllerBase
|
||||
{
|
||||
|
||||
@@ -2,11 +2,13 @@ using Asp.Versioning;
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Swashbuckle.AspNetCore.Annotations;
|
||||
using IamService.API.Application.Common;
|
||||
using IamService.API.Application.Commands.Users;
|
||||
using IamService.API.Application.Queries.Users;
|
||||
using IamService.Domain.AggregatesModel.UserAggregate;
|
||||
|
||||
namespace IamService.API.Controllers;
|
||||
|
||||
@@ -17,19 +19,22 @@ namespace IamService.API.Controllers;
|
||||
[ApiController]
|
||||
[ApiVersion("1.0")]
|
||||
[Route("api/v{version:apiVersion}/users")]
|
||||
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
|
||||
[Authorize(AuthenticationSchemes = "Bearer")]
|
||||
[SwaggerTag("User management endpoints - requires authentication")]
|
||||
public class UsersController : ControllerBase
|
||||
{
|
||||
private readonly IMediator _mediator;
|
||||
private readonly ILogger<UsersController> _logger;
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
|
||||
public UsersController(
|
||||
IMediator mediator,
|
||||
ILogger<UsersController> logger)
|
||||
ILogger<UsersController> logger,
|
||||
UserManager<ApplicationUser> userManager)
|
||||
{
|
||||
_mediator = mediator;
|
||||
_logger = logger;
|
||||
_userManager = userManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -238,6 +243,89 @@ public class UsersController : ControllerBase
|
||||
Roles = roles
|
||||
}));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// EN: Get user roles by user ID.
|
||||
/// VI: Lấy danh sách roles của user theo ID.
|
||||
/// </summary>
|
||||
/// <param name="id">User ID</param>
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
/// <returns>List of user roles</returns>
|
||||
[HttpGet("{id:guid}/roles")]
|
||||
[SwaggerOperation(
|
||||
Summary = "Get user roles",
|
||||
Description = "Retrieves all roles assigned to a specific user.",
|
||||
OperationId = "GetUserRoles")]
|
||||
[SwaggerResponse(StatusCodes.Status200OK, "Successfully retrieved user roles", typeof(ApiResponse<UserRolesDto>))]
|
||||
[SwaggerResponse(StatusCodes.Status401Unauthorized, "Authentication required")]
|
||||
[SwaggerResponse(StatusCodes.Status404NotFound, "User not found")]
|
||||
[ProducesResponseType(typeof(ApiResponse<UserRolesDto>), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<IActionResult> GetUserRoles(
|
||||
[FromRoute, SwaggerParameter("User ID", Required = true)] Guid id,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var user = await _userManager.FindByIdAsync(id.ToString());
|
||||
if (user == null)
|
||||
{
|
||||
return NotFound(ApiResponse<UserRolesDto>.Fail("USER_NOT_FOUND", $"User with ID {id} not found."));
|
||||
}
|
||||
|
||||
var roles = await _userManager.GetRolesAsync(user);
|
||||
|
||||
return Ok(ApiResponse<UserRolesDto>.Ok(new UserRolesDto
|
||||
{
|
||||
UserId = id.ToString(),
|
||||
Roles = roles
|
||||
}));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// EN: Get user permissions by user ID.
|
||||
/// VI: Lấy danh sách permissions của user theo ID.
|
||||
/// </summary>
|
||||
/// <param name="id">User ID</param>
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
/// <returns>List of user permissions</returns>
|
||||
[HttpGet("{id:guid}/permissions")]
|
||||
[SwaggerOperation(
|
||||
Summary = "Get user permissions",
|
||||
Description = "Retrieves all permissions for a specific user (derived from roles).",
|
||||
OperationId = "GetUserPermissions")]
|
||||
[SwaggerResponse(StatusCodes.Status200OK, "Successfully retrieved user permissions", typeof(ApiResponse<UserPermissionsDto>))]
|
||||
[SwaggerResponse(StatusCodes.Status401Unauthorized, "Authentication required")]
|
||||
[SwaggerResponse(StatusCodes.Status404NotFound, "User not found")]
|
||||
[ProducesResponseType(typeof(ApiResponse<UserPermissionsDto>), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<IActionResult> GetUserPermissions(
|
||||
[FromRoute, SwaggerParameter("User ID", Required = true)] Guid id,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var user = await _userManager.FindByIdAsync(id.ToString());
|
||||
if (user == null)
|
||||
{
|
||||
return NotFound(ApiResponse<UserPermissionsDto>.Fail("USER_NOT_FOUND", $"User with ID {id} not found."));
|
||||
}
|
||||
|
||||
var roles = await _userManager.GetRolesAsync(user);
|
||||
var claims = await _userManager.GetClaimsAsync(user);
|
||||
|
||||
// EN: Extract permissions from claims
|
||||
// VI: Lấy permissions từ claims
|
||||
var permissions = claims
|
||||
.Where(c => c.Type == "permission")
|
||||
.Select(c => c.Value)
|
||||
.ToList();
|
||||
|
||||
return Ok(ApiResponse<UserPermissionsDto>.Ok(new UserPermissionsDto
|
||||
{
|
||||
UserId = id.ToString(),
|
||||
Roles = roles,
|
||||
Permissions = permissions
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -279,3 +367,47 @@ public class DeleteUserResult
|
||||
/// </summary>
|
||||
public string Message { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// EN: User roles response DTO.
|
||||
/// VI: DTO response cho danh sách roles của user.
|
||||
/// </summary>
|
||||
public class UserRolesDto
|
||||
{
|
||||
/// <summary>
|
||||
/// EN: User ID.
|
||||
/// VI: ID của user.
|
||||
/// </summary>
|
||||
public string UserId { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// EN: List of role names assigned to the user.
|
||||
/// VI: Danh sách tên roles được gán cho user.
|
||||
/// </summary>
|
||||
public IEnumerable<string> Roles { get; set; } = Enumerable.Empty<string>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// EN: User permissions response DTO.
|
||||
/// VI: DTO response cho danh sách permissions của user.
|
||||
/// </summary>
|
||||
public class UserPermissionsDto
|
||||
{
|
||||
/// <summary>
|
||||
/// EN: User ID.
|
||||
/// VI: ID của user.
|
||||
/// </summary>
|
||||
public string UserId { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// EN: List of role names assigned to the user.
|
||||
/// VI: Danh sách tên roles được gán cho user.
|
||||
/// </summary>
|
||||
public IEnumerable<string> Roles { get; set; } = Enumerable.Empty<string>();
|
||||
|
||||
/// <summary>
|
||||
/// EN: List of permission names assigned to the user.
|
||||
/// VI: Danh sách tên permissions được gán cho user.
|
||||
/// </summary>
|
||||
public IEnumerable<string> Permissions { get; set; } = Enumerable.Empty<string>();
|
||||
}
|
||||
|
||||
@@ -113,40 +113,26 @@ public static class DependencyInjection
|
||||
.AddAspNetIdentity<ApplicationUser>()
|
||||
.AddDeveloperSigningCredential(); // EN: Use certificate in production / VI: Dùng certificate trong production
|
||||
|
||||
// EN: Add JWT Bearer authentication for API endpoints
|
||||
// VI: Thêm JWT Bearer authentication cho API endpoints
|
||||
// EN: Add JWT Bearer authentication for API endpoints using local IdentityServer
|
||||
// VI: Thêm JWT Bearer authentication cho API endpoints sử dụng IdentityServer cục bộ
|
||||
// EN: AddLocalApi() allows JWT validation without external metadata calls (for self-hosted IdentityServer)
|
||||
// VI: AddLocalApi() cho phép JWT validation mà không cần gọi metadata bên ngoài (cho self-hosted IdentityServer)
|
||||
services.AddAuthentication()
|
||||
.AddJwtBearer(options =>
|
||||
.AddLocalApi("Bearer", options =>
|
||||
{
|
||||
// EN: Configure to validate tokens from local IdentityServer
|
||||
// VI: Cấu hình để validate tokens từ IdentityServer cục bộ
|
||||
options.Authority = configuration["IdentityServer:Authority"] ?? "https://localhost:5001";
|
||||
options.Audience = "iam-api";
|
||||
options.RequireHttpsMetadata = false; // EN: Set to true in production / VI: Đặt true trong production
|
||||
|
||||
// EN: Disable metadata validation for testing/development
|
||||
// VI: Tắt metadata validation cho testing/development
|
||||
options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
|
||||
{
|
||||
ValidateAudience = false, // EN: Disable for flexibility / VI: Tắt để linh hoạt
|
||||
ValidateIssuer = false, // EN: Disable for testing / VI: Tắt cho testing
|
||||
ValidateLifetime = true,
|
||||
RequireSignedTokens = true,
|
||||
ValidateIssuerSigningKey = true
|
||||
};
|
||||
|
||||
// EN: Disable metadata address requirement if in testing environment
|
||||
// VI: Tắt yêu cầu metadata address nếu trong testing environment
|
||||
if (string.Equals(environmentName, "Testing", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
options.MetadataAddress = string.Empty;
|
||||
options.TokenValidationParameters.ValidateIssuerSigningKey = false;
|
||||
options.TokenValidationParameters.RequireSignedTokens = false;
|
||||
// EN: ASP.NET Core 8+ requires JsonWebToken, not JwtSecurityToken
|
||||
// VI: ASP.NET Core 8+ yêu cầu JsonWebToken, không phải JwtSecurityToken
|
||||
options.TokenValidationParameters.SignatureValidator = (token, parameters) => new Microsoft.IdentityModel.JsonWebTokens.JsonWebToken(token);
|
||||
}
|
||||
options.ExpectedScope = "openid";
|
||||
});
|
||||
|
||||
// EN: Configure authorization policies
|
||||
// VI: Cấu hình authorization policies
|
||||
services.AddAuthorization(options =>
|
||||
{
|
||||
options.AddPolicy("LocalApi", policy =>
|
||||
{
|
||||
policy.AddAuthenticationSchemes("Bearer");
|
||||
policy.RequireAuthenticatedUser();
|
||||
});
|
||||
});
|
||||
|
||||
// EN: Register repositories
|
||||
// VI: Đăng ký repositories
|
||||
|
||||
Reference in New Issue
Block a user