1

我正在尝试按照本教程进行操作,并且正在努力将实现转换为 GraphQL。

本地策略.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;
  }
}

身份验证.type.ts

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

  @Field()
  password: string;
}

身份验证.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
  }
}

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

4

2 回答 2

3

问题出在你的LogInWithCredentialsGuard.

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

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

这是一个工作代码片段

@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;
}
于 2021-07-15T10:09:22.523 回答
0

我已经能够使用这样的警卫成功登录:

@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;
  }
}
于 2021-11-03T12:11:04.540 回答