Skip to content

Instantly share code, notes, and snippets.

@DimosthenisK
Created December 17, 2019 10:14
Show Gist options
  • Star 13 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save DimosthenisK/db21929a137d3e6c147f0bda3ecfbda6 to your computer and use it in GitHub Desktop.
Save DimosthenisK/db21929a137d3e6c147f0bda3ecfbda6 to your computer and use it in GitHub Desktop.
NestJS Guard + Decorator that allows user access limit to his own resources
import { SetMetadata } from '@nestjs/common';
export interface SelfDecoratorParams {
userIDParam: string;
allowAdmins?: boolean;
}
export const Self = (params: SelfDecoratorParams | string) =>
SetMetadata(
'selfParams',
typeof params == 'string' ? { userIDParam: params } : params,
);
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { Observable } from 'rxjs';
import { Reflector } from '@nestjs/core';
import { roles, User } from '../../user.dbentity';
import { SelfDecoratorParams } from '../decorators/self.decorator';
@Injectable()
export class SelfGuard implements CanActivate {
constructor(private readonly reflector: Reflector) {}
canActivate(
context: ExecutionContext,
): boolean | Promise<boolean> | Observable<boolean> {
const request = context.switchToHttp().getRequest();
const user = request.user as User; //Use passport authentication strategy
//Priority on method meta
let selfParams = this.reflector.get<SelfDecoratorParams>(
'selfParams',
context.getHandler(),
);
if (!selfParams)
//Check for class meta
selfParams = this.reflector.get<SelfDecoratorParams>(
'selfParams',
context.getClass(),
);
//If still no meta, pass
if (!selfParams) return true;
let allowAdmins = selfParams.allowAdmins || true;
let userIDParam = selfParams.userIDParam;
if (!user) return false;
if (request.params[userIDParam] == user.id) return true;
if (allowAdmins && user.role == roles.SUPERUSER) return true;
}
}
import {
Controller,
Param,
Body,
UseInterceptors,
Patch,
UseGuards,
Req,
} from '@nestjs/common';
import { SelfGuard } from '../authentication/guards/self.guard';
import { Request } from 'express';
import { User } from '../user.dbentity';
import { Self } from '../authentication/decorators/self.decorator';
@Self('id') //here "id" notes that the user id is on the "id" request parameter
@UseGuards(SelfGuard)
@Controller()
export class UserController {
constructor(service: UserService) {}
@Get('/sampleResource')
//You may also use the @Self decorator here for method-specific functionality
async getSampleResource() {
return "Sample resource";
}
@Get('/sampleResource-adminCanAccess')
@Self({userIDParam: 'id', allowAdmins: true})
async getAdminSampleResource() {
return "Sample resource";
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment