refactor: Cập nhật cấu hình các tuyến đường (routes) của dịch vụ IAM và API xác thực phía client, đồng thời loại bỏ tệp sao lưu RBAC cũ.

This commit is contained in:
Ho Ngoc Hai
2026-01-04 14:35:12 +07:00
parent a383d8772e
commit d4f6115179
6 changed files with 137 additions and 244 deletions

View File

@@ -69,7 +69,7 @@ export const authApi = {
* VI: Lấy hồ sơ người dùng đã xác thực hiện tại
*/
getMe: async (): Promise<ApiResponse<UserResponse>> => {
return apiClient.get('/users/me');
return apiClient.get('/identity/profile');
},
/**
@@ -104,17 +104,17 @@ export const authApi = {
// EN: Set the token in the client
// VI: Đặt token trong client
apiClient.setAuthToken(accessToken);
// EN: Fetch user profile to complete authentication
// VI: Lấy thông tin user để hoàn tất xác thực
const userResponse = await apiClient.get('/users/me');
const userResponse = await apiClient.get('/identity/profile');
if (userResponse.success && userResponse.data) {
// EN: Store refresh token if available (OAuth might not provide refresh token)
// VI: Lưu refresh token nếu có (OAuth có thể không cung cấp refresh token)
// Note: For OAuth, we only have access token, refresh token handling depends on backend
// Ghi chú: Đối với OAuth, chúng ta chỉ có access token, xử lý refresh token phụ thuộc vào backend
return {
success: true,
data: {
@@ -125,7 +125,7 @@ export const authApi = {
timestamp: new Date().toISOString(),
};
}
throw new Error('Failed to fetch user profile / Không thể lấy thông tin người dùng');
},

View File

@@ -33,14 +33,26 @@ app.use(
cors({
origin: appConfig.corsOrigin,
credentials: true,
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization', 'x-correlation-id', 'x-request-id'],
exposedHeaders: ['x-correlation-id'],
})
);
// EN: Rate limiting
// VI: Giới hạn số lượng request
// EN: Rate limiting (more permissive for development)
// VI: Giới hạn số lượng request (cho phép nhiều hơn trong development)
const limiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 100,
windowMs: 15 * 60 * 1000, // 15 minutes
max: appConfig.nodeEnv === 'production' ? 100 : 1000, // 1000 for dev, 100 for prod
message: {
success: false,
error: {
code: 'RATE_LIMIT_EXCEEDED',
message: 'Too many requests, please try again later',
},
},
standardHeaders: true,
legacyHeaders: false,
});
app.use('/api', limiter);

View File

@@ -615,5 +615,43 @@ export const createGovernanceRouter = (): Router => {
*/
router.get('/reports/risk-overview', authenticate(), requirePermission('governance', 'read'), reportingController.riskOverview.bind(reportingController));
// =============================================================================
// EN: Alias Routes (for backward compatibility)
// VI: Routes Alias (để tương thích ngược)
// =============================================================================
/**
* @swagger
* /api/{version}/governance/audit-logs:
* get:
* summary: Get audit logs (stub)
* description: Get audit logs - not yet implemented
* tags: [Governance]
* security:
* - bearerAuth: []
*/
router.get('/audit-logs', authenticate(), requirePermission('governance', 'read'), (req, res) => {
res.status(501).json({
success: false,
error: {
code: 'NOT_IMPLEMENTED',
message: 'Audit logs endpoint is not yet implemented / Endpoint audit logs chưa được triển khai'
},
timestamp: new Date().toISOString()
});
});
/**
* @swagger
* /api/{version}/governance/compliance:
* get:
* summary: Get compliance status (alias)
* description: Alias for /reports/compliance-status
* tags: [Governance]
* security:
* - bearerAuth: []
*/
router.get('/compliance', authenticate(), requirePermission('governance', 'read'), reportingController.complianceStatus.bind(reportingController));
return router;
};

View File

@@ -1248,5 +1248,53 @@ export const createIdentityRouter = (): Router => {
*/
router.delete('/groups/:id/members/:userId', authenticate(), requirePermission('identity', 'update'), groupController.removeMember.bind(groupController));
// =============================================================================
// EN: Alias Routes (for backward compatibility)
// VI: Routes Alias (để tương thích ngược)
// =============================================================================
/**
* @swagger
* /api/{version}/identity/users:
* post:
* summary: Create user (stub)
* description: Create a new user - not yet implemented
* tags: [Identity - Users]
* security:
* - bearerAuth: []
*/
router.post('/users', authenticate(), requirePermission('identity', 'create'), (req, res) => {
res.status(501).json({
success: false,
error: {
code: 'NOT_IMPLEMENTED',
message: 'Create user endpoint is not yet implemented / Endpoint tạo người dùng chưa được triển khai'
},
timestamp: new Date().toISOString()
});
});
/**
* @swagger
* /api/{version}/identity/profile:
* get:
* summary: Get current user profile
* description: Get profile of currently authenticated user
* tags: [Identity - Profile]
* security:
* - bearerAuth: []
*/
router.get('/profile', authenticate(), (req, res) => {
const userId = (req as any).user?.id || (req as any).user?.sub;
if (!userId) {
return res.status(401).json({
success: false,
error: { code: 'UNAUTHORIZED', message: 'Authentication required' }
});
}
// Redirect to /users/:id/profile
return res.redirect(`/api/v1/identity/users/${userId}/profile`);
});
return router;
};

View File

@@ -216,5 +216,34 @@ export const createMfaRouter = (): Router => {
*/
router.get('/devices', authenticate(), mfaController.getMFADevices.bind(mfaController));
// =============================================================================
// EN: Alias Routes (for backward compatibility)
// VI: Routes Alias (để tương thích ngược)
// =============================================================================
/**
* @swagger
* /api/{version}/mfa/setup:
* post:
* summary: Setup MFA (alias for /totp/enable)
* description: Alias endpoint for setting up MFA
* tags: [MFA]
* security:
* - bearerAuth: []
*/
router.post('/setup', authenticate(), mfaController.enableTOTP.bind(mfaController));
/**
* @swagger
* /api/{version}/mfa/verify:
* post:
* summary: Verify MFA (alias for /totp/verify)
* description: Alias endpoint for verifying MFA code
* tags: [MFA]
* security:
* - bearerAuth: []
*/
router.post('/verify', authenticate(), mfaController.verifyAndEnableTOTP.bind(mfaController));
return router;
};

View File

@@ -1,234 +0,0 @@
import { Router } from 'express';
import { authenticate } from '../../middlewares/auth.middleware';
import { requirePermission } from '../../middlewares/rbac.middleware';
import { rbacController } from './rbac.controller';
/**
* EN: Create and configure RBAC routes
* VI: Tạo và cấu hình routes cho RBAC
*/
export const createRbacRouter = (): Router => {
const router = Router();
/**
* @swagger
* /api/{version}/rbac/permissions:
* get:
* summary: Get user permissions
* description: Get list of permissions assigned to the current user
* tags: [RBAC]
* security:
* - bearerAuth: []
* parameters:
* - in: path
* name: version
* required: true
* schema:
* type: string
* default: v1
* description: API version
* responses:
* 200:
* description: Permissions retrieved successfully
* content:
* application/json:
* schema:
* allOf:
* - $ref: '#/components/schemas/ApiResponse'
* - type: object
* properties:
* data:
* type: array
* items:
* type: string
* 401:
* description: Unauthorized
*/
router.get('/permissions', authenticate(), rbacController.getUserPermissions.bind(rbacController));
/**
* @swagger
* /api/{version}/rbac/roles/assign:
* post:
* summary: Assign role to user
* description: Assign a specific role to a user. Requires 'rbac:assign' permission.
* tags: [RBAC]
* security:
* - bearerAuth: []
* parameters:
* - in: path
* name: version
* required: true
* schema:
* type: string
* default: v1
* description: API version
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* required: [userId, roleId]
* properties:
* userId:
* type: string
* roleId:
* type: string
* responses:
* 200:
* description: Role assigned successfully
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/ApiResponse'
* 401:
* description: Unauthorized
* 403:
* description: Forbidden - Insufficient permissions
* 404:
* description: User or Role not found
*/
router.post('/roles/assign', authenticate(), requirePermission('rbac', 'assign'), rbacController.assignRole.bind(rbacController));
/**
* @swagger
* /api/{version}/rbac/roles/revoke:
* post:
* summary: Revoke role from user
* description: Revoke a specific role from a user. Requires 'rbac:revoke' permission.
* tags: [RBAC]
* security:
* - bearerAuth: []
* parameters:
* - in: path
* name: version
* required: true
* schema:
* type: string
* default: v1
* description: API version
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* required: [userId, roleId]
* properties:
* userId:
* type: string
* roleId:
* type: string
* responses:
* 200:
* description: Role revoked successfully
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/ApiResponse'
* 401:
* description: Unauthorized
* 403:
* description: Forbidden - Insufficient permissions
* 404:
* description: User or Role not found
*/
router.post('/roles/revoke', authenticate(), requirePermission('rbac', 'revoke'), rbacController.revokeRole.bind(rbacController));
/**
* @swagger
* /api/{version}/rbac/permissions/grant:
* post:
* summary: Grant permission to role
* description: Grant a specific permission to a role. Requires 'rbac:grant' permission.
* tags: [RBAC]
* security:
* - bearerAuth: []
* parameters:
* - in: path
* name: version
* required: true
* schema:
* type: string
* default: v1
* description: API version
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* required: [roleId, permissionId]
* properties:
* roleId:
* type: string
* permissionId:
* type: string
* responses:
* 200:
* description: Permission granted successfully
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/ApiResponse'
* 401:
* description: Unauthorized
* 403:
* description: Forbidden - Insufficient permissions
* 404:
* description: Role or Permission not found
*/
router.post('/permissions/grant', authenticate(), requirePermission('rbac', 'grant'), rbacController.grantPermission.bind(rbacController));
/**
* @swagger
* /api/{version}/rbac/permissions/check:
* get:
* summary: Check permission
* description: Check if the current user has a specific permission
* tags: [RBAC]
* security:
* - bearerAuth: []
* parameters:
* - in: path
* name: version
* required: true
* schema:
* type: string
* default: v1
* description: API version
* - in: query
* name: resource
* required: true
* schema:
* type: string
* - in: query
* name: action
* required: true
* schema:
* type: string
* responses:
* 200:
* description: Permission check result
* content:
* application/json:
* schema:
* allOf:
* - $ref: '#/components/schemas/ApiResponse'
* - type: object
* properties:
* data:
* type: object
* properties:
* allowed:
* type: boolean
* 401:
* description: Unauthorized
* 403:
* description: Forbidden
*/
router.get('/permissions/check', authenticate(), rbacController.checkPermission.bind(rbacController));
return router;
};