NestJS 获取使用 JWT 身份验证的 GraphQL 解析器中的当前用户 [英] NestJS Get current user in GraphQL resolver authenticated with JWT
问题描述
我目前正在将带有 Passport.js 的 JWT 身份验证实施到 NestJS 应用程序中.
I am currently implementing JWT authentication with Passport.js into a NestJS application.
在我的一些 GraphQL 解析器中,我需要访问当前经过身份验证的用户.我知道护照会将经过身份验证的用户附加到请求对象(至少我希望这是正确的),但我不知道如何在解析器中访问请求对象.
In some of my GraphQL resolvers I need to access the currently authenticated user. I know that passport will attach the authenticated user to the request object (at least I hope that this is correct), but I do not know how to access the request object inside a resolver.
我关注了这个问题 https://github.com/nestjs/nest/issues/1326 和提到的链接 https://github.com/ForetagInc/fullstack-boilerplate/tree/master/apps/api/src/app/auth 里面的问题.我在 GraphQL 解析器方法中看到了一些使用 @Res() res: Request
作为方法参数的代码,但我总是得到 undefined
for res
.
I followed the issue https://github.com/nestjs/nest/issues/1326 and the mentioned link https://github.com/ForetagInc/fullstack-boilerplate/tree/master/apps/api/src/app/auth inside the issue. I saw some code that uses @Res() res: Request
as a method parameter in the GraphQL resolver methods, but I always get undefined
for res
.
这些是我目前的实现:
GQLAuth
import { Injectable, ExecutionContext } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { GqlExecutionContext } from '@nestjs/graphql';
import { ExecutionContextHost } from '@nestjs/core/helpers/execution-context-host';
import { AuthenticationError } from 'apollo-server-core';
@Injectable()
export class GqlAuthGuard extends AuthGuard('jwt') {
canActivate(context: ExecutionContext) {
const ctx = GqlExecutionContext.create(context);
const { req } = ctx.getContext();
console.log(req);
return super.canActivate(new ExecutionContextHost([req]));
}
handleRequest(err: any, user: any) {
if (err || !user) {
throw err || new AuthenticationError('GqlAuthGuard');
}
return user;
}
}
需要访问当前用户的解析器
import { UseGuards, Req } from '@nestjs/common';
import { Resolver, Query, Args, Mutation, Context } from '@nestjs/graphql';
import { Request } from 'express';
import { UserService } from './user.service';
import { User } from './models/user.entity';
import { GqlAuthGuard } from '../auth/guards/gql-auth.guard';
@Resolver(of => User)
export class UserResolver {
constructor(private userService: UserService) {}
@Query(returns => User)
@UseGuards(GqlAuthGuard)
whoami(@Req() req: Request) {
console.log(req);
return this.userService.findByUsername('aw');
}
}
JWT 策略
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';
import { AuthService } from './auth.service';
import { JwtPayload } from './interfaces/jwt-payload.interface';
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(private readonly authService: AuthService) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: process.env.SECRET,
});
}
async validate(payload: JwtPayload) {
const user = await this.authService.validateUser(payload);
if (!user) {
throw new UnauthorizedException();
}
return user;
}
}
授权和创建 JWT 令牌工作正常.GraphQL 守卫也适用于不需要访问用户的方法.但是对于需要访问当前经过身份验证的用户的方法,我看不出有什么办法.
Authorization and creating JWT tokens works fine. GraphQL guard also works fine for methods that do not need to access the user. But for methods that need access to the currently authenticated user, I see no way of getting it.
有没有办法完成这样的事情?
Is there a way to accomplish something like this ?
推荐答案
终于找到答案了... https://github.com/nestjs/graphql/issues/48#issuecomment-420693225 为我指明了创建用户装饰器
Finally found the answer ... https://github.com/nestjs/graphql/issues/48#issuecomment-420693225 pointed me into the right direction of creating a user decorator
// user.decorator.ts
import { createParamDecorator } from '@nestjs/common';
export const CurrentUser = createParamDecorator(
(data, req) => req.user,
);
然后在我的解析器方法中使用它:
And then use this in my resolver method:
import { User as CurrentUser } from './user.decorator';
@Query(returns => User)
@UseGuards(GqlAuthGuard)
whoami(@CurrentUser() user: User) {
console.log(user);
return this.userService.findByUsername(user.username);
}
现在一切都按预期进行.所以这个答案的所有功劳都归于 https://github.com/cschroeter
Now everything works as expected. So all credits of this answer goes to https://github.com/cschroeter
这篇关于NestJS 获取使用 JWT 身份验证的 GraphQL 解析器中的当前用户的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!