Korer
Korer

Reputation: 197

How to protect BullBoard `/queues` path

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

Answers (0)

Related Questions