@@ -57,7 +57,7 @@ export class JwtAuthGuard implements CanActivate {
|
||||
audience: process.env.AUTHENTIK_AUDIENCE,
|
||||
});
|
||||
|
||||
const identity = new IdentityData(
|
||||
const identity = new IdentityData(
|
||||
payload.sub as string,
|
||||
(payload as any).preferred_username as string | undefined,
|
||||
(payload as any).email as string | undefined,
|
||||
@@ -65,6 +65,8 @@ export class JwtAuthGuard implements CanActivate {
|
||||
);
|
||||
|
||||
request.identity = identity;
|
||||
// mark as external (verified by Authentik JWKS)
|
||||
(request as any).identitySource = 'external';
|
||||
this.logger.debug(`Verified token using external JWKS. sub=${payload.sub}`);
|
||||
return true;
|
||||
} catch (err) {
|
||||
@@ -81,7 +83,7 @@ export class JwtAuthGuard implements CanActivate {
|
||||
}
|
||||
|
||||
try {
|
||||
const payload = jwt.verify(token, secret) as any;
|
||||
const payload = jwt.verify(token, secret) as any;
|
||||
|
||||
const identity = new IdentityData(
|
||||
payload.sub as string,
|
||||
@@ -91,6 +93,8 @@ export class JwtAuthGuard implements CanActivate {
|
||||
);
|
||||
|
||||
request.identity = identity;
|
||||
// mark as internal (verified by RayLab internal secret)
|
||||
(request as any).identitySource = 'internal';
|
||||
this.logger.debug(`Verified token using internal secret. sub=${payload.sub}`);
|
||||
return true;
|
||||
} catch (err: any) {
|
||||
|
||||
@@ -2,11 +2,16 @@ import { Request } from 'express';
|
||||
import { UserData } from '../../../modules/identity/domain/entities/user.entity';
|
||||
import { IdentityData } from './identity-data';
|
||||
|
||||
export type IdentitySource = 'internal' | 'external';
|
||||
|
||||
export interface AuthenticatedRequest extends Request {
|
||||
// Identity comes from the external Identity Provider (Authentik)
|
||||
// JwtAuthGuard must set request.identity = payload
|
||||
identity?: IdentityData;
|
||||
|
||||
// Indicate verification source: 'external' => verified via Authentik JWKS; 'internal' => verified via RayLab internal secret
|
||||
identitySource?: IdentitySource;
|
||||
|
||||
// After CurrentUserGuard resolves the user from repository, it must set request.currentUser = User Domain
|
||||
currentUser?: UserData;
|
||||
}
|
||||
@@ -1,15 +1,18 @@
|
||||
import { Injectable, CanActivate, ExecutionContext, UnauthorizedException } from '@nestjs/common';
|
||||
import { Injectable, CanActivate, ExecutionContext, UnauthorizedException, Inject } from '@nestjs/common';
|
||||
import { SyncIdentityHandler } from '../../application/handlers/user/sync-identity.handler';
|
||||
import { IdentityData } from '../../../../core/auth/interfaces/identity-data';
|
||||
import { IUser } from '../../domain/repositories/user.interface';
|
||||
import { AuthenticatedRequest, IdentitySource } from '../../../../core/auth/interfaces/authenticated-request.interface';
|
||||
|
||||
@Injectable()
|
||||
export class CurrentUserGuard implements CanActivate {
|
||||
constructor(
|
||||
private readonly syncIdentityHandler: SyncIdentityHandler,
|
||||
@Inject(IUser) private readonly userRepository: IUser,
|
||||
) {}
|
||||
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
const request = context.switchToHttp().getRequest() as any;
|
||||
const request = context.switchToHttp().getRequest() as AuthenticatedRequest & { raylabContext?: any };
|
||||
|
||||
// Prefer RequestContext produced by AuthenticationService
|
||||
const ctx = request.raylabContext as any;
|
||||
@@ -25,6 +28,19 @@ export class CurrentUserGuard implements CanActivate {
|
||||
throw new UnauthorizedException('Identity is missing.');
|
||||
}
|
||||
|
||||
const source: IdentitySource | undefined = request.identitySource;
|
||||
|
||||
if (source === 'internal') {
|
||||
try {
|
||||
const user = await this.userRepository.getById(identity.sub);
|
||||
request.currentUser = user;
|
||||
return true;
|
||||
} catch (e) {
|
||||
// convert repository not-found to Unauthorized
|
||||
throw new UnauthorizedException('User not found.');
|
||||
}
|
||||
}
|
||||
|
||||
const user = await this.syncIdentityHandler.execute(identity);
|
||||
|
||||
// attach domain user as currentUser
|
||||
|
||||
Reference in New Issue
Block a user