All checks were successful
Deploy API Server / build-and-deploy (push) Successful in 9s
- Add AdminRole enum (SUPER_ADMIN/ADMIN/OPERATIONS/DEVELOPER/READONLY) with hierarchy
- Add PasswordService (bcryptjs, 12 rounds), AdminTokenService (type=admin JWT)
- Add AdminAuthService: login/lockout/refresh/logout with audit logging
- Add AdminAuthController: /admin-api/auth/{login,refresh,logout,me}
- Add AdminAuthGuard: validates type=admin, user status, session, lockout
- Add AdminRolesGuard + @AdminRoles() decorator for RBAC
- Add AdminAuditService for audit log persistence
- Add AdminLoginRateLimit (10 req/15min per IP)
- Add prisma/seed.ts for SUPER_ADMIN initialization via env vars
- Update JwtAuthGuard to skip /admin-api/* and /internal/* paths
- Update main.ts to exclude admin-api/internal from global 'api' prefix
- Update jwt.config.ts with admin JWT secrets and expiry config
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
59 lines
2.4 KiB
TypeScript
59 lines
2.4 KiB
TypeScript
import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth } from '@nestjs/swagger';
|
|
import { Controller, Post, Body, Get, HttpCode, HttpStatus, Req, UseGuards } from '@nestjs/common';
|
|
import { AdminAuthService } from './admin-auth.service';
|
|
import { AdminLoginDto, AdminRefreshDto } from './dto';
|
|
import { AdminPublic } from '../../common/decorators/admin-public.decorator';
|
|
import { AdminAuthGuard } from '../../common/guards/admin-auth.guard';
|
|
import { AdminRolesGuard } from '../../common/guards/admin-roles.guard';
|
|
import { AdminLoginRateLimit } from '../../common/decorators/rate-limit.decorator';
|
|
import type { Request } from 'express';
|
|
|
|
@ApiTags('admin-auth')
|
|
@Controller('admin-api/auth')
|
|
@UseGuards(AdminAuthGuard, AdminRolesGuard)
|
|
export class AdminAuthController {
|
|
constructor(private readonly adminAuthService: AdminAuthService) {}
|
|
|
|
@AdminPublic()
|
|
@Post('login')
|
|
@HttpCode(HttpStatus.OK)
|
|
@AdminLoginRateLimit()
|
|
@ApiOperation({ summary: '管理员登录' })
|
|
@ApiResponse({ status: 200, description: '登录成功' })
|
|
@ApiResponse({ status: 401, description: '邮箱或密码错误' })
|
|
@ApiResponse({ status: 403, description: '账号已禁用或锁定' })
|
|
async login(@Body() dto: AdminLoginDto, @Req() req: Request) {
|
|
return this.adminAuthService.login(dto.email, dto.password, req.ip, req.headers['user-agent']);
|
|
}
|
|
|
|
@AdminPublic()
|
|
@Post('refresh')
|
|
@HttpCode(HttpStatus.OK)
|
|
@ApiOperation({ summary: '刷新管理员令牌' })
|
|
@ApiResponse({ status: 200, description: '刷新成功' })
|
|
@ApiResponse({ status: 401, description: '刷新令牌无效' })
|
|
async refresh(@Body() dto: AdminRefreshDto, @Req() req: Request) {
|
|
return this.adminAuthService.refresh(dto.refreshToken, req.ip, req.headers['user-agent']);
|
|
}
|
|
|
|
@Post('logout')
|
|
@HttpCode(HttpStatus.OK)
|
|
@ApiBearerAuth()
|
|
@ApiOperation({ summary: '管理员退出登录' })
|
|
@ApiResponse({ status: 200, description: '退出成功' })
|
|
async logout(@Req() req: Request, @Body() dto: AdminRefreshDto) {
|
|
const adminUser = (req as any).adminUser;
|
|
await this.adminAuthService.logout(adminUser.id, dto.refreshToken);
|
|
return { success: true, message: '已退出登录' };
|
|
}
|
|
|
|
@Get('me')
|
|
@ApiBearerAuth()
|
|
@ApiOperation({ summary: '获取当前管理员信息' })
|
|
@ApiResponse({ status: 200, description: '成功' })
|
|
async getMe(@Req() req: Request) {
|
|
const adminUser = (req as any).adminUser;
|
|
return this.adminAuthService.getMe(adminUser.id);
|
|
}
|
|
}
|