diff --git a/apps/web-client/src/services/api/auth.api.ts b/apps/web-client/src/services/api/auth.api.ts index 7168eee2..38cfb7b1 100644 --- a/apps/web-client/src/services/api/auth.api.ts +++ b/apps/web-client/src/services/api/auth.api.ts @@ -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> => { - 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'); }, diff --git a/services/iam-service/src/app.ts b/services/iam-service/src/app.ts index 40bcb933..b08552b3 100644 --- a/services/iam-service/src/app.ts +++ b/services/iam-service/src/app.ts @@ -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); diff --git a/services/iam-service/src/modules/governance/governance.routes.ts b/services/iam-service/src/modules/governance/governance.routes.ts index 59ca24a8..3111955b 100644 --- a/services/iam-service/src/modules/governance/governance.routes.ts +++ b/services/iam-service/src/modules/governance/governance.routes.ts @@ -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; }; diff --git a/services/iam-service/src/modules/identity/identity.routes.ts b/services/iam-service/src/modules/identity/identity.routes.ts index e30a3b27..0ca60dc4 100644 --- a/services/iam-service/src/modules/identity/identity.routes.ts +++ b/services/iam-service/src/modules/identity/identity.routes.ts @@ -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; }; diff --git a/services/iam-service/src/modules/mfa/mfa.routes.ts b/services/iam-service/src/modules/mfa/mfa.routes.ts index 4c9eb348..5bd7c803 100644 --- a/services/iam-service/src/modules/mfa/mfa.routes.ts +++ b/services/iam-service/src/modules/mfa/mfa.routes.ts @@ -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; }; diff --git a/services/iam-service/src/modules/rbac/rbac.routes.ts.bak b/services/iam-service/src/modules/rbac/rbac.routes.ts.bak deleted file mode 100644 index 321a758f..00000000 --- a/services/iam-service/src/modules/rbac/rbac.routes.ts.bak +++ /dev/null @@ -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; -};