first commit
This commit is contained in:
56
libs/api/identity/presenters/src/lib/auth/auth.guard.ts
Normal file
56
libs/api/identity/presenters/src/lib/auth/auth.guard.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import {
|
||||
CanActivate,
|
||||
ExecutionContext,
|
||||
ForbiddenException,
|
||||
Injectable,
|
||||
UnauthorizedException,
|
||||
} from '@nestjs/common';
|
||||
import { Reflector } from '@nestjs/core';
|
||||
import {
|
||||
IdentityService,
|
||||
InvalidAccessTokenError,
|
||||
} from '@task-stream/api/identity/application';
|
||||
import { extractBearerToken, getAuthRequest } from './auth-request';
|
||||
import { IS_PUBLIC, REQUIRED_APP_ROLES } from './auth.decorators';
|
||||
|
||||
/** Global guard: every HTTP/GraphQL operation needs a valid Pireon token unless @Public(). */
|
||||
@Injectable()
|
||||
export class AuthGuard implements CanActivate {
|
||||
constructor(
|
||||
private readonly reflector: Reflector,
|
||||
private readonly identity: IdentityService,
|
||||
) {}
|
||||
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
const targets = [context.getHandler(), context.getClass()];
|
||||
if (this.reflector.getAllAndOverride<boolean>(IS_PUBLIC, targets))
|
||||
return true;
|
||||
|
||||
const req = getAuthRequest(context);
|
||||
// WebSocket subscriptions are authenticated once in connection_init.
|
||||
if (!req.user) {
|
||||
const token = extractBearerToken(req.headers['authorization']);
|
||||
if (!token) throw new UnauthorizedException('Missing bearer token');
|
||||
try {
|
||||
req.user = await this.identity.resolveSession(token);
|
||||
req.accessToken = token;
|
||||
} catch (error) {
|
||||
if (error instanceof InvalidAccessTokenError)
|
||||
throw new UnauthorizedException(error.message);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
const roles = this.reflector.getAllAndOverride<string[]>(
|
||||
REQUIRED_APP_ROLES,
|
||||
targets,
|
||||
);
|
||||
const user = req.user;
|
||||
if (roles?.length && user && !roles.some((role) => user.hasAppRole(role))) {
|
||||
throw new ForbiddenException(
|
||||
`Requires one of the app roles: ${roles.join(', ')}`,
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user