[ ] Regression
[ ] Bug report
[ ] Feature request
[X] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.
import { ExtractJwt, Strategy } from 'passport-jwt';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { JwtPayload } from '../models/jwt-payload.interface';
import { UserService } from '../../user/services/user.service';
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(private readonly userService: UserService) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: '________',
});
}
async validate(payload: JwtPayload, done) {
const user = await this.userService.findOneByJwtPayload(payload);
if (!user) {
return done(new UnauthorizedException(), false);
}
done(null, user);
}
}
user.service.ts
export class UserService {
...
async findOneByJwtPayload(payload: JwtPayload): Promise<UserEntity> {
return await this.userModel
.findOne({
username: payload.username,
email: payload.email,
})
.exec();
}
...
}
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { DatabaseModule } from '../database/database.module';
import { RootModule } from '../../modules/root.module';
import { APP_GUARD } from '@nestjs/core';
import { RoleGuard } from '../../modules/role/guards/role.guard';
import { JwtStrategy } from '../../modules/auth/providers/jwt.strategy';
@Module({
imports: [DatabaseModule, RootModule],
controllers: [AppController],
providers: [
JwtStrategy,
AppService,
{
provide: APP_GUARD,
useClass: RoleGuard,
},
],
})
export class AppModule {}
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
@Injectable()
export class RoleGuard implements CanActivate {
constructor(private readonly reflector: Reflector,) {}
canActivate(context: ExecutionContext): boolean {
const handlerAuthorities = this.reflector.get<string[]>('authorities', context.getHandler()) || [];
const classAuthorities = this.reflector.get<string[]>('authorities', context.getClass()) || [];
const authorities = [...handlerAuthorities, ...classAuthorities];
const request = context.switchToHttp().getRequest();
const user = request.user;
console.log('role guard --> ', user);
setTimeout(() => {
console.log('role guard setTimeout --> ', request.user);
}, 20);
if (!authorities || !authorities.length) {
return true;
}
const userAuthoritiesInRoles = user ? (user.roles || []).reduce((all, role) => all.concat(role.authorities), []) : [];
const userAuthorities = user ? (user.authorities || []).concat(userAuthoritiesInRoles) : [];
const hasRole = () => userAuthorities.some(role => !!authorities.find(item => item === role));
return user && userAuthorities && hasRole();
}
}
[Nest] 5819 - 2018-6-17 12:11:17 [NestApplication] Nest application successfully started +0ms
role guard --> undefined
role guard setTimeout --> { _id: 5b2691ed13d0b911a720155c,
username: 'bhenav',
password: '11111111',
firstName: 'kutbettin',
lastName: 'yavuz',
email: '[email protected]',
customers: [],
__v: 0 }
Nest version: 5.2.0
For Tooling issues:
- Node version: 8.11.2
- Platform: Mac
Others:
yarn version: 1.7.0
npm version: 5.6.0
you haven't stated what the issue is at all, you just threw code at us expecting us to understand what the problem is. please follow the template and _explain_ what the problem is so we can help you.
Guard is always before...
@wbhob, I want to JWT provider running before the guard. How can I do it?
also as I wrote console result :)
for this use case, i feel like putting authentication logic in a middleware would be better, as it runs before the guard.
Ok, thank you for everything.
I am confused. In general, This should be configured that run authentication strategy first before RoleGuard to run.
When someone follow the examples in the documentation, they will always meet this issue.
The root cause is that APP_GUARD has the highest priority among guards. Thereafter, the implementation of the authentication strategy becomes meaningless.
So... In currently, middleware isn't good solution. because, middleware is global processor and It is also configured to run on public APIs. Also there is actually no way to know about the execution context. (Whether the method have reflect-meta.)
IMHO, There are 2 Options for resolving.
Separately, it may be necessary to document the execution order of pipes and guards about global, method and multiple defined cases.
My two cents here, I've been trying to follow the documentation to implement the RolesGuard, but the RolesGuard never received the request.user
as the execution order was incorrect as APP_GUARD
is higher priority and executed eagerly to local module providers.
I've resolved this by not setting the RolesGuard
provider as APP_GUARD
like so:
@Module({
imports: [DatabaseModule, RootModule],
controllers: [AppController],
providers: [
JwtStrategy,
AppService,
RolesGuard,
],
})
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Most helpful comment
I am confused. In general, This should be configured that run authentication strategy first before RoleGuard to run.
When someone follow the examples in the documentation, they will always meet this issue.
The root cause is that APP_GUARD has the highest priority among guards. Thereafter, the implementation of the authentication strategy becomes meaningless.
So... In currently, middleware isn't good solution. because, middleware is global processor and It is also configured to run on public APIs. Also there is actually no way to know about the execution context. (Whether the method have reflect-meta.)
IMHO, There are 2 Options for resolving.
Separately, it may be necessary to document the execution order of pipes and guards about global, method and multiple defined cases.