fix(security): harden auth — rate limiting, admin audit logging, JWT aud/iss
- Add @Throttle (5 req/hour per IP) on register, login, refresh endpoints
- Add audit logging in RolesGuard for failed admin access attempts (userId, role, IP, action)
- Add audience ('goodgo-api') and issuer ('goodgo-platform') claims to JWT tokens
- Validate aud/iss in JwtStrategy to prevent cross-service token reuse
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
import { Injectable, type CanActivate, type ExecutionContext } from '@nestjs/common';
|
||||
import { Injectable, Logger, type CanActivate, type ExecutionContext } from '@nestjs/common';
|
||||
import { Reflector } from '@nestjs/core';
|
||||
import { type UserRole } from '@prisma/client';
|
||||
import { ROLES_KEY } from '../decorators/roles.decorator';
|
||||
|
||||
@Injectable()
|
||||
export class RolesGuard implements CanActivate {
|
||||
private readonly logger = new Logger(RolesGuard.name);
|
||||
|
||||
constructor(private readonly reflector: Reflector) {}
|
||||
|
||||
canActivate(context: ExecutionContext): boolean {
|
||||
@@ -17,7 +19,20 @@ export class RolesGuard implements CanActivate {
|
||||
return true;
|
||||
}
|
||||
|
||||
const { user } = context.switchToHttp().getRequest();
|
||||
return requiredRoles.includes(user?.role);
|
||||
const request = context.switchToHttp().getRequest();
|
||||
const user = request.user;
|
||||
const hasRole = requiredRoles.includes(user?.role);
|
||||
|
||||
if (!hasRole) {
|
||||
const ip = request.ip || request.headers?.['x-forwarded-for'] || 'unknown';
|
||||
const handler = context.getHandler().name;
|
||||
const controller = context.getClass().name;
|
||||
this.logger.warn(
|
||||
`Access denied: userId=${user?.sub ?? 'unknown'}, role=${user?.role ?? 'none'}, ` +
|
||||
`required=${requiredRoles.join(',')}, action=${controller}.${handler}, ip=${ip}`,
|
||||
);
|
||||
}
|
||||
|
||||
return hasRole;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user