Reputation: 197
I addedd BullBoard
module to my nestsj app like below:
BullBoardModule.forRoot({
route: '/queues',
adapter: ExpressAdapter,
middleware: (req, res, next) => {},
}),
and I want to allow access to only admin users. In my app I have guards like these two where the first one attaches user to the request and second one checks if the user has a specific role
import { CanActivate, ExecutionContext, Injectable, UnauthorizedException } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { Reflector } from '@nestjs/core';
import { JwtService } from '@nestjs/jwt';
import { IConfiguration } from '@src/config/configuration';
import { IS_PUBLIC_KEY } from '@src/core/decorators/public-decorator';
import { UserService } from '@src/modules/user/user.service';
@Injectable()
export class AuthGuard implements CanActivate {
constructor(
private jwtService: JwtService,
private configService: ConfigService<IConfiguration>,
private reflector: Reflector,
private userService: UserService /* Injecting UsersService to fetch user data */,
) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [
context.getHandler(),
context.getClass(),
]);
const request = context.switchToHttp().getRequest();
const token = this.extractTokenFromHeader(request);
try {
const payload = await this.jwtService.verifyAsync(token, {
secret: this.configService.get('jwt.secretKey', { infer: true }),
});
const user = await this.userService.findOne({
where: { id: payload.id },
select: ['id', 'username', 'displayName', 'role', 'phoneNumber', 'company', 'tokens', 'email'],
});
/* 💡 We're assigning the payload to the request object here
so that we can access it in our route handlers */
request['user'] = user;
// /* Logout if logged in on another account */
// const storedSessionId = await this.redisClient.get(`user:${payload.id}:session`);
// if (storedSessionId !== payload.sessionId) {
// this.sseService.sendEvent({
// event: SseEvents.Logout,
// userId: user.id,
// data: { sessionId: payload.sessionId, time: new Date().getTime() },
// });
// }
} catch (e) {
if (isPublic) request['user'] = null;
else throw new UnauthorizedException(e);
}
return true;
}
private extractTokenFromHeader(request: Request): string | undefined {
const [type, token] = request.headers['authorization']?.split(' ') ?? [];
return type === 'Bearer' ? token : undefined;
}
}
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
@Injectable()
export class RoleGuard implements CanActivate {
constructor(private _role: string | string[]) {}
canActivate(context: ExecutionContext) {
console.log('Role guard');
const request = context.switchToHttp().getRequest();
const user = request.user;
if (!Array.isArray(this._role)) {
return user && user.role === this._role;
}
return user && this._role.some((role) => role === user.role);
}
}
Can I somehow use them in this middleware
option? What is the easiest way to do that? Now for each endpont I can add for example
@ApiPut('company', { roles: [Roles.TEACHER, Roles.USER], description: 'Update company', type: OutputUserDto })
where
export function ApiPut(
path: string,
{
description,
type,
useAuthGuard = true,
roles,
}: {
description: string;
type: Type<unknown> | Function | [Function] | string;
useAuthGuard?: boolean;
roles?: Array<Roles>;
},
): MethodDecorator {
return applyDecorators(
Put(path),
ApiOperation({ description: description }),
ApiOkResponse({ type: type }),
...(useAuthGuard ? [ApiBearerAuth(), ...(roles ? [UseGuards(new RoleGuard(roles))] : [])] : [Public()]),
);
}
Can I do similar thing for queues
and somehow add such an endpoint?
Upvotes: 1
Views: 115