diff --git a/server/app.module.ts b/server/app.module.ts index 41446f8..d0135c1 100644 --- a/server/app.module.ts +++ b/server/app.module.ts @@ -9,6 +9,7 @@ import { RolesGuard } from './providers/guards/roles.guard'; import { JwtService } from './providers/services/jwt.service'; import { RolesService } from './providers/services/roles.service'; import { UsersService } from './providers/services/users.service'; +import { GuardUtil } from './providers/util/guard.util'; @Module({ imports: [TypeOrmModule.forRoot(config), UsersModule], @@ -17,6 +18,7 @@ import { UsersService } from './providers/services/users.service'; UsersService, RolesService, JwtService, + GuardUtil, { provide: APP_GUARD, useClass: AuthGuard }, // auth guard should come before roles guard { provide: APP_GUARD, useClass: RolesGuard }, // otherwise users won't be authenticated before roles check ], diff --git a/server/database/seeds.ts b/server/database/seeds.ts index 94e69ef..4e9acc4 100644 --- a/server/database/seeds.ts +++ b/server/database/seeds.ts @@ -18,7 +18,7 @@ export default class Seeds implements Seeder { // only insert roles if not present already const role = await roleRepository.findOne(roleObj); if (!role) { - console.log(`Creating role '${role.key}'`); + console.log(`Creating role '${roleObj.key}'`); await roleRepository.insert(roleObj); } else { console.log(`Role '${role.key}' already exists`); diff --git a/server/providers/guards/auth.guard.ts b/server/providers/guards/auth.guard.ts index 8c03ad8..722094b 100644 --- a/server/providers/guards/auth.guard.ts +++ b/server/providers/guards/auth.guard.ts @@ -1,24 +1,17 @@ import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common'; import { JwtService } from '../services/jwt.service'; -import { SKIP_KEY } from 'server/decorators/skip.decorator'; -import { Reflector } from '@nestjs/core'; -import { Class } from 'server/dto/class.dto'; +import { GuardUtil } from '../util/guard.util'; @Injectable() export class AuthGuard implements CanActivate { - constructor(private reflector: Reflector, private jwtService: JwtService) {} + constructor(private guardUtil: GuardUtil, private jwtService: JwtService) {} canActivate(context: ExecutionContext) { - const skippedGuards = this.reflector.getAllAndOverride[]>(SKIP_KEY, [ - context.getHandler(), - context.getClass(), - ]); - if (skippedGuards) { - const skippedGuard = skippedGuards.find((guard) => this instanceof guard); - if (skippedGuard) { - return true; - } + // Handlers and Controllers can both skip this guard in the event that + if (this.guardUtil.shouldSkip(this, context)) { + return true; } + const req = context.switchToHttp().getRequest(); const authHeader = req.headers.authorization; if (!authHeader) return false; diff --git a/server/providers/guards/roles.guard.ts b/server/providers/guards/roles.guard.ts index 3ecc392..17aa224 100644 --- a/server/providers/guards/roles.guard.ts +++ b/server/providers/guards/roles.guard.ts @@ -5,7 +5,7 @@ import { JwtBodyDto } from 'server/dto/jwt_body.dto'; import { RoleKey } from 'server/entities/role.entity'; import { RolesService } from '../services/roles.service'; import { UsersService } from '../services/users.service'; -import { some } from 'lodash'; +import { intersection, isEmpty } from 'lodash'; @Injectable() export class RolesGuard implements CanActivate { @@ -16,7 +16,6 @@ export class RolesGuard implements CanActivate { context.getHandler(), context.getClass(), ]); - console.log(requiredRoles); if (!requiredRoles) { return true; @@ -26,12 +25,6 @@ export class RolesGuard implements CanActivate { if (!jwtBody) return false; // unauthenticated users are not authorized - const user = await this.usersService.find(jwtBody.userId, ['userRoles']); - const roles = await this.rolesService.findByKey(...requiredRoles); - const roleMatches = user.userRoles.map((userRole) => { - return !!roles.find((role) => role.id === userRole.roleId); - }); - - return some(roleMatches); + return !isEmpty(intersection(jwtBody.roles, requiredRoles)); } } diff --git a/server/providers/util/guard.util.ts b/server/providers/util/guard.util.ts new file mode 100644 index 0000000..64d4627 --- /dev/null +++ b/server/providers/util/guard.util.ts @@ -0,0 +1,17 @@ +import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common'; +import { Reflector } from '@nestjs/core'; +import { SKIP_KEY } from 'server/decorators/skip.decorator'; +import { Class } from 'server/dto/class.dto'; + +@Injectable() +export class GuardUtil { + constructor(private reflector: Reflector) {} + + public shouldSkip(guard: CanActivate, context: ExecutionContext) { + const skippedGuards = this.reflector.getAllAndOverride[]>(SKIP_KEY, [ + context.getHandler(), + context.getClass(), + ]); + return !!(skippedGuards && skippedGuards.find((SkippedGuard) => guard instanceof SkippedGuard)); + } +}