This commit is contained in:
2026-01-14 01:10:01 +03:00
parent 24c5581d7b
commit 2ce092aa59
40 changed files with 2001 additions and 297 deletions

View File

@ -0,0 +1,11 @@
import { Module } from '@nestjs/common';
import { PassportModule } from '@nestjs/passport';
import { JwtStrategy } from './jwt.strategy';
import { JwtAuthGuard } from './jwt-auth.guard';
@Module({
imports: [PassportModule.register({ defaultStrategy: 'jwt' })],
providers: [JwtStrategy, JwtAuthGuard],
exports: [JwtAuthGuard],
})
export class AuthModule {}

View File

@ -0,0 +1,4 @@
import { SetMetadata } from '@nestjs/common';
export const IS_PUBLIC_KEY = 'isPublic';
export const Public = () => SetMetadata(IS_PUBLIC_KEY, true);

View File

@ -0,0 +1,4 @@
export * from './auth.module';
export * from './jwt-auth.guard';
export * from './jwt.strategy';
export * from './decorators/public.decorator';

View File

@ -0,0 +1,24 @@
import { Injectable, ExecutionContext } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { Reflector } from '@nestjs/core';
import { IS_PUBLIC_KEY } from './decorators/public.decorator';
@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {
constructor(private reflector: Reflector) {
super();
}
canActivate(context: ExecutionContext) {
const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [
context.getHandler(),
context.getClass(),
]);
if (isPublic) {
return true;
}
return super.canActivate(context);
}
}

View File

@ -0,0 +1,51 @@
import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';
import { passportJwtSecret } from 'jwks-rsa';
import { ConfigService } from '@nestjs/config';
export interface JwtPayload {
sub: string;
preferred_username: string;
email: string;
given_name?: string;
family_name?: string;
}
export interface AuthUser {
userId: string;
username: string;
email: string;
firstName?: string;
lastName?: string;
}
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(configService: ConfigService) {
const realmUrl = configService.get<string>('KEYCLOAK_REALM_URL');
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
issuer: realmUrl,
algorithms: ['RS256'],
secretOrKeyProvider: passportJwtSecret({
cache: true,
rateLimit: true,
jwksRequestsPerMinute: 5,
jwksUri: `${realmUrl}/protocol/openid-connect/certs`,
}),
});
}
validate(payload: JwtPayload): AuthUser {
return {
userId: payload.sub,
username: payload.preferred_username,
email: payload.email,
firstName: payload.given_name,
lastName: payload.family_name,
};
}
}