【问题标题】:NestJS/GraphQL/Passport - getting unauthorised error from guardNestJS/GraphQL/Passport - 从警卫那里得到未经授权的错误
【发布时间】:2021-09-24 03:54:17
【问题描述】:

我正在尝试遵循 tutorial,并且正在努力将实现转换为 GraphQL。

local.strategy.ts

@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
  constructor(private readonly authenticationService: AuthenticationService) {
    super();
  }

  async validate(email: string, password: string): Promise<any> {
    const user = await this.authenticationService.getAuthenticatedUser(
      email,
      password,
    );

    if (!user) throw new UnauthorizedException();

    return user;
  }
}

local.guard.ts

@Injectable()
export class LogInWithCredentialsGuard extends AuthGuard('local') {
  async canActivate(context: ExecutionContext): Promise<boolean> {
    const ctx = GqlExecutionContext.create(context);
    const { req } = ctx.getContext();
    req.body = ctx.getArgs();

    await super.canActivate(new ExecutionContextHost([req]));
    await super.logIn(req);
    return true;
  }
}

authentication.type.ts

@InputType()
export class AuthenticationInput {
  @Field()
  email: string;

  @Field()
  password: string;
}

authentication.resolver.ts

@UseGuards(LogInWithCredentialsGuard)
@Mutation(() => User, { nullable: true })
logIn(
  @Args('variables')
  _authenticationInput: AuthenticationInput,
  @Context() req: any,
) {
  return req.user;
}

变异

mutation {
  logIn(variables: {
    email: "email@email.com",
    password: "123123"
  } ) {
    id
    email
  }
}

即使上述凭据是正确的,我也会收到未经授权的错误。

【问题讨论】:

    标签: graphql nestjs passport-local nestjs-passport


    【解决方案1】:

    问题出在你的LogInWithCredentialsGuard

    您不应该覆盖canAcitavte 方法,您所要做的就是使用适当的graphql args 更新请求,因为在API 请求的情况下,passport 会自动从req.body 获取您的凭据,但如果graphql 执行上下文不同所以你必须在 req.body 中手动设置你的参数,并使用 getRequest 方法。

    由于 graphql 和 rest api 的执行上下文不同,你必须确保你的守卫在这两种情况下都能正常工作,无论是控制器还是突变。

    这是一个工作代码sn-p

    @Injectable()
    export class LogInWithCredentialsGuard extends AuthGuard('local') {
      // Override this method so it can be used in graphql
      getRequest(context: ExecutionContext) {
        const ctx = GqlExecutionContext.create(context);
        const gqlReq = ctx.getContext().req;
        if (gqlReq) {
          const { variables } = ctx.getArgs();
          gqlReq.body = variables;
          return gqlReq;
        }
        return context.switchToHttp().getRequest();
      }
    }
    

    你的突变会像

    @UseGuards(LogInWithCredentialsGuard)
    @Mutation(() => User, { nullable: true })
    logIn(
      @Args('variables')
      _authenticationInput: AuthenticationInput,
      @Context() context: any, // <----------- it's not request
    ) {
      return context.req.user;
    }
    

    【讨论】:

    • 谢谢,守卫工作,但它不会设置会话 cookie 而不覆盖 canActivate 方法。
    【解决方案2】:

    我已经能够通过这样的守卫成功登录:

    @Injectable()
    export class LocalGqlAuthGuard extends AuthGuard('local') {
      constructor() {
        super();
      }
      getRequest(context: ExecutionContext) {
        const ctx = GqlExecutionContext.create(context);
        const req = ctx.getContext().req;
        req.body = ctx.getArgs();
        return req;
      }
      async canActivate(context: ExecutionContext) {
        await super.canActivate(context);
        const ctx = GqlExecutionContext.create(context);
        const req = ctx.getContext().req;
        await super.logIn(req);
        return true;
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2019-12-19
      • 2017-10-07
      • 2017-01-12
      • 2018-02-02
      • 2022-12-24
      • 2018-11-05
      • 1970-01-01
      • 2017-04-17
      • 2022-11-26
      相关资源
      最近更新 更多