4
I use Passport and GraphQL and if I do my own custom guard to get user’s roles it just doesn’t work. I don’t have access to the user from the request in a Guard, is that intentional? I think it should be part of the request (I’m totally new to NestJS), so why I can’t get it? I would like to get the user’s roles directly from the user object and only allow users with Admin for specific routes like the full list of users.
This is my GraphQL guard, the console log always return undefined
@Injectable()
export class GraphqlPassportAuthGuard extends AuthGuard('jwt') {
roles: string[];
constructor(roles?: string | string[]) {
super();
this.roles = Array.isArray(roles) ? roles : [roles];
}
canActivate(context: ExecutionContext): boolean {
const ctx = GqlExecutionContext.create(context);
const req = ctx.getContext().req;
console.log('graphql guard user', req && req.user)
return true;
}
getRequest(context: ExecutionContext) {
const ctx = GqlExecutionContext.create(context);
const req = ctx.getContext().req;
console.log('graphql guard user', req && req.user)
return req;
}
}
and I try using it with following code
export const CurrentUser = createParamDecorator(
(data, [root, args, ctx, info]) => {
return ctx.req.user;
},
);
@Resolver()
export class UsersResolver {
constructor() { }
@Query(() => UserDto)
@UseGuards(GraphqlPassportAuthGuard)
whoAmI(@CurrentUser() user: User) {
return user;
}
}
app.module.ts
@Module({
imports: [
GraphQLModule.forRoot({
autoSchemaFile: 'schema.gql',
context: ({ req }) => ({ req }),
}),
// ...
});
I can get the user from the @CurrentUser()
with a Custom Decorator but I can’t get the user object inside the guard. I’m trying to get the user from the request, but is that possible in a Guard or not? I tried so many things, I don’t know what to do anymore.
I also tried to do another Roles Guard with different code and again I’m trying to get the user from the request and I can’t get the user from the request.
@Injectable()
export class RolesGuard implements CanActivate {
constructor(private readonly reflector: Reflector) { }
canActivate(context: ExecutionContext): boolean {
const handler = context.getHandler();
const http = context.switchToHttp();
const request = context.switchToHttp().getRequest();
const roles = this.reflector.get<string[]>('roles', context.getHandler());
console.log('rolesGuard', roles, request && request.user)
if (!roles || !request || !request.user) {
return true;
}
const user = request && request.user;
const hasRole = () =>
user.roles.some(role => !!roles.find(item => item === role));
return user && user.roles && hasRole();
}
}
1 Answer
Reset to default
5
On your GraphqlPassportAuthGuard.canActivate()
you should call await super.canActivate(context)
, and change the return value type for Promise<boolean>
, this is where the @nestjs/passport AuthGuard
put the user in the Request object.
If, for some reason, you don’t want the guard to throw when the user is not authenticated, you have to override also the AuthGuard.handleRequest(err, user, info, context)
2
-
Sorry for the delay, I just tried this and I still have the same result
undefined
, am I supposed to still calli the same 2 lines after thesuper.canActivate
? That 2nd linectx.getContext().req
still doesn't have the user that I'm looking for. Would you mind providing the full code of thecanActive
method? Am I suppose to delete something or call something else? I'm totally new to NestJS, I'm a little confused. My main goal is the get the user's role and block the user if he doesn't have necessary role– ghiscodingDec 7, 2019 at 21:27
-
1
You should
await
for super.canActivate since it returns a Promise, sorry I didn't mention in my original answer. So make your definition ofcanActivate
async
and callawait super.canActivate(context)
. Remember also to change the return type toPromise<boolean>
– GheroDec 8, 2019 at 21:35
Not the answer you're looking for? Browse other questions tagged
or ask your own question.
or ask your own question.
|