我将使用Nest.js结合GraphQL和Passport来创建认证处理
在Nest.js中使用Passport作为认证库的方法在官方文档中有介绍,并以在GraphQL中的实现作为参考。
但是,在GraphQL中的实现仅仅是作为参考,不能单独运行。
本次实现将致力于在GraphQL中实际实现基于用户名和密码的认证。
1. 创建基础项目
使用以下命令创建一个Nest.js项目。
$ npm i -g @nestjs/cli
$ nest new passport-sample
$ cd passport-sample
项目创建后,根据身份验证需求的步骤安装所需的库。
2. 创建模块
根据实施Passport策略,创建必要的护照样本模块并进行示例实现各种逻辑。
在这里将创建以下文件。
-
- users/users.service.ts
-
- users/users.module.ts
-
- auth/auth.service.ts
- auth/auth.module.ts
3. 创建本地策略
根据Passport local的实现,我们将实现一个执行验证的LocalStrategy来进行认证。
LocalStrategy的实现如下所示。
import { Strategy } from 'passport-local';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { AuthService } from './auth.service';
@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
constructor(private authService: AuthService) {
super();
}
async validate(username: string, password: string): Promise<any> {
const user = await this.authService.validateUser(username, password);
if (!user) {
throw new UnauthorizedException();
}
return user;
}
}
按照步骤,也更新AuthModule。
4. 创建本地身份验证保护(LocalAuthGuard)。
在公式文档中,LocalAuthGuard是这样的:
import { Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
@Injectable()
export class LocalAuthGuard extends AuthGuard('local') {}
然而,由于此实施方式无法正确地将从GraphQL传递的参数传递给LocalStrategy,因此认证会失败。
因此,要在GraphQL中实现该LocalAuthGuard,需要使用getRequest方法将参数映射如下。
import { Injectable, ExecutionContext } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { GqlExecutionContext } from '@nestjs/graphql';
@Injectable()
export class LocalAuthGuard extends AuthGuard('local') {
getRequest(context: ExecutionContext) {
const ctx = GqlExecutionContext.create(context);
const gqlReq = ctx.getContext().req;
if (gqlReq) {
gqlReq.body = ctx.getArgs();
return gqlReq;
}
return context.switchToHttp().getRequest();
}
}
5. 将Mutaion设为LocalAuthGuard.
首先,我们要定义一个用于返回用户信息的模型。
import { Field, Int, ObjectType } from '@nestjs/graphql';
@ObjectType()
export class User {
@Field(type => Int)
userId: number;
@Field()
username: string;
}
在app.resolver.ts中创建一个名为login的Mutation,并设置LocalAuthGuard。
import { UseGuards, UseInterceptors } from '@nestjs/common';
import { Resolver, Mutation, Args } from '@nestjs/graphql';
import { LocalAuthGuard } from './auth/local-auth.guard';
import { User } from './users/models/user.model';
@Resolver()
export class AppResolver {
@UseGuards(LocalAuthGuard)
@Mutation(() => User)
async login(
@Request() req,
@Args({ name: 'username', type: () => Int }) _: number,
@Args({ name: 'password' }) _: string
): Promise<User> {
return req.user
}
}
用这个方法,你可以在GraphQl中使用Passport进行身份验证。