forked from Shared/esg
initial commit
This commit is contained in:
34
src/auth/guards/api-key.guard.ts
Normal file
34
src/auth/guards/api-key.guard.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import {
|
||||
CanActivate,
|
||||
ExecutionContext,
|
||||
Injectable,
|
||||
UnauthorizedException,
|
||||
} from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { Request } from 'express';
|
||||
import { API_KEY_HEADER } from '../../common/constants/app.constants';
|
||||
|
||||
/**
|
||||
* API key authentication for inquiry endpoints.
|
||||
* Expects x-api-key header matching configured API_KEY.
|
||||
*/
|
||||
@Injectable()
|
||||
export class ApiKeyGuard implements CanActivate {
|
||||
constructor(private readonly configService: ConfigService) {}
|
||||
|
||||
canActivate(context: ExecutionContext): boolean {
|
||||
const request = context.switchToHttp().getRequest<Request>();
|
||||
const apiKey = request.headers[API_KEY_HEADER] as string | undefined;
|
||||
const expected = this.configService.get<string>('auth.apiKey');
|
||||
|
||||
if (!expected) {
|
||||
throw new UnauthorizedException('API key authentication is not configured');
|
||||
}
|
||||
|
||||
if (!apiKey || apiKey !== expected) {
|
||||
throw new UnauthorizedException('Invalid or missing API key');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
45
src/auth/guards/inquiry-access.guard.ts
Normal file
45
src/auth/guards/inquiry-access.guard.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { CanActivate, ExecutionContext, ForbiddenException, Injectable } from '@nestjs/common';
|
||||
import { Reflector } from '@nestjs/core';
|
||||
import { Request } from 'express';
|
||||
import { ADMIN_ROLES } from '../../common/enums/role.enum';
|
||||
import { InquiryType } from '../../common/enums/inquiry-type.enum';
|
||||
import { INQUIRY_ACCESS_KEY } from '../constants/auth.constants';
|
||||
import { AuthenticatedUser } from '../interfaces/authenticated-user.interface';
|
||||
|
||||
/**
|
||||
* Validates that the user may call a specific inquiry endpoint.
|
||||
* ADMIN / SUPER_ADMIN bypass — external USER clients need allowedInquiries.
|
||||
*/
|
||||
@Injectable()
|
||||
export class InquiryAccessGuard implements CanActivate {
|
||||
constructor(private readonly reflector: Reflector) {}
|
||||
|
||||
canActivate(context: ExecutionContext): boolean {
|
||||
const requiredInquiry = this.reflector.getAllAndOverride<InquiryType>(INQUIRY_ACCESS_KEY, [
|
||||
context.getHandler(),
|
||||
context.getClass(),
|
||||
]);
|
||||
|
||||
if (!requiredInquiry) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const request = context.switchToHttp().getRequest<Request & { user: AuthenticatedUser }>();
|
||||
const user = request.user;
|
||||
|
||||
if (!user) {
|
||||
throw new ForbiddenException('Authentication required');
|
||||
}
|
||||
|
||||
if (ADMIN_ROLES.includes(user.role)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const inquiryKey = requiredInquiry as string;
|
||||
if (!user.allowedInquiries.includes(inquiryKey)) {
|
||||
throw new ForbiddenException(`Access denied for inquiry: ${inquiryKey}`);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
21
src/auth/guards/jwt-auth.guard.ts
Normal file
21
src/auth/guards/jwt-auth.guard.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { ExecutionContext, Injectable, UnauthorizedException } from '@nestjs/common';
|
||||
import { AuthGuard } from '@nestjs/passport';
|
||||
import { JWT_ACCESS_STRATEGY } from '../constants/auth.constants';
|
||||
|
||||
/**
|
||||
* Protects routes with Passport JWT access strategy.
|
||||
*/
|
||||
@Injectable()
|
||||
export class JwtAuthGuard extends AuthGuard(JWT_ACCESS_STRATEGY) {
|
||||
override handleRequest<TUser>(
|
||||
err: Error | null,
|
||||
user: TUser | false,
|
||||
_info: unknown,
|
||||
_context: ExecutionContext,
|
||||
): TUser {
|
||||
if (err || !user) {
|
||||
throw err ?? new UnauthorizedException('Unauthorized');
|
||||
}
|
||||
return user;
|
||||
}
|
||||
}
|
||||
34
src/auth/guards/roles.guard.ts
Normal file
34
src/auth/guards/roles.guard.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { CanActivate, ExecutionContext, ForbiddenException, Injectable } from '@nestjs/common';
|
||||
import { Reflector } from '@nestjs/core';
|
||||
import { Request } from 'express';
|
||||
import { ROLES_KEY } from '../constants/auth.constants';
|
||||
import { AuthenticatedUser } from '../interfaces/authenticated-user.interface';
|
||||
import { Role } from '../../common/enums/role.enum';
|
||||
|
||||
/**
|
||||
* Enforces @Roles() metadata against the authenticated user's role.
|
||||
*/
|
||||
@Injectable()
|
||||
export class RolesGuard implements CanActivate {
|
||||
constructor(private readonly reflector: Reflector) {}
|
||||
|
||||
canActivate(context: ExecutionContext): boolean {
|
||||
const requiredRoles = this.reflector.getAllAndOverride<Role[]>(ROLES_KEY, [
|
||||
context.getHandler(),
|
||||
context.getClass(),
|
||||
]);
|
||||
|
||||
if (!requiredRoles?.length) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const request = context.switchToHttp().getRequest<Request & { user: AuthenticatedUser }>();
|
||||
const user = request.user;
|
||||
|
||||
if (!user || !requiredRoles.includes(user.role)) {
|
||||
throw new ForbiddenException('Insufficient role permissions');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user