携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第4天,点击查看活动详情
本系列文章将涉及到的技术有Nest.js、Typescript、Vite、Vue、Antdv、MySql。本人也是个菜鸡前端,初涉全栈,第一次写文,希望各位大大多多包涵,有什么建议可以提出来互相交流。
-【Passport】
passport.js是Nodejs中的一个做登录验证的中间件,可以与Express等Web框架无缝集成。
策略是passport中最重要的概念。passport模块本身不能做认证,所有的认证方法都以策略模式封装为插件,需要某种认证时安装对应策略即可。
策略模式是一种设计模式,它将算法和对象分离开来,通过加载不同的算法来实现不同的行为,适用于相关类的成员相同但行为不同的场景,比如在passport中,认证所需的字段都是用户名、邮箱、密码等,但认证方法是不同的。关于策略模式,本文不详细展开,想了解的推荐阅读Javascript中的策略模式,或者更广泛意义上的策略模式。
我们这次就使用passport中的jwt策略来对接口进行验证。
-【Nest守卫】
守卫顾名思义,就像你进入办公大楼的时候,那个让你出示核酸码的保安一样,他必须确保你的核酸正常,你才能通行。 要了解Nest的守卫,你就得了解整个请求的处理过程。
从客户端发送一个请求,到服务器接收请求内容,触发绑定的函数并且执行相关逻辑完毕,然后返回内容给客户端的整个过程大体上要经过如下几个步骤:
发送请求->中间件->守卫->拦截器->管道->方法逻辑->拦截器->返回
中间件就像是一个洋葱一样不断的包裹再包裹,一层层调用,我们都知道在Express中,其实守卫,拦截器,管道都称作中间件,而Nest只不过把这些步骤给拆分出来细化了。我们的验证逻辑最适合就是放在守卫里去实现。
-【Jwt策略具体实现】
首先我们安装相关的包
$ yarn add --save @nestjs/passport passport
$ yarn add @nestjs/jwt passport-jwt
$ yarn add @types/passport-jwt --save-dev
在根目录添加guards和strategies目录和对应的文件
guards/jwt-auth.guard.ts
// guards/jwt-auth.guard.ts
import { Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {}
strategies/jwt.strategy.ts
// strategies/jwt.strategy.ts jwt策略配置
import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';
import { jwtConstants } from './constants';
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor() {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: jwtConstants.secret,
});
}
// 该方法参数表示通过守卫后解析token得到的内容,返回值将传入控制器方法参数
async validate(payload: any) {
return {
id: payload.id,
username: payload.username,
name: payload.name,
companyId: payload.companyId,
};
}
}
strategies/constants.ts
export const jwtConstants = {
secret: 'booklend123', // jwt生成的密钥可以随便定
};
然后我们修改对应的逻辑,这一步就是在登录成功后生成token
// 只显示修改部分
...
constructor(
private readonly authService: AuthService,
private readonly jwtService: JwtService,
) {}
// 要在这里注入对象,就必须在Auth模块中注册
...
@Get('checkUser')
async checkUser(@Request() req: any) {
console.log(req.query);
const { username, password } = req.query;
const result: any = await this.authService.checkUser({
username,
});
const isOk = bcryptjs.compareSync(password, result.password);
if (!isOk) {
throw new HttpException('用户验证失败', HttpStatus.UNAUTHORIZED);
}
return {
// 表示最终需要把哪些字段值存入token
access_token: this.jwtService.sign({
id: result.id,
username: result.username,
name: result.name,
companyId: result.companyId,
}),
};
}
最后一定不能忘记注册到模块中去,因为我整个项目都会使用,所以我直接注册到根模块中,
// 只显示更改部分
import { JwtModule } from '@nestjs/jwt';
import { PassportModule } from '@nestjs/passport';
import { jwtConstants } from './strategies/constants';
import { JwtStrategy } from './strategies/jwt.strategy';
@Module({
imports: [
...
PassportModule,
JwtModule.register({
secret: jwtConstants.secret,
signOptions: { expiresIn: '60s' },
}),
...
],
controllers: [AppController],
providers: [AppService, JwtStrategy],
})
export class AppModule {}
接下来修改一下前端的代码,登录后保存token,再加上一个测试的接口,
message.success('登录成功')
// 登录后存储access_token
localStorage.setItem('access_token', r.data.access_token)
请求的时候headers请务必带上Authorization: Bearer token
let token = localStorage.getItem('access_token')
axios.get('http://localhost:3000/lend/test',{
headers: {
Authorization: `Bearer ${token}`
}
})
这样就完成了jwt认证的功能,后面只需要在适当的地方开启守卫就好了,可以直接加在控制器上,或者全局,根据需求来吧。
@UseGuards(AuthGuard('jwt'))
到这里可以通过守卫验证了,但是我突然发现要修改守卫返回的提示却无从下手,有知道的小伙伴可以分享一下经验吗?
下一篇我们去实现一些业务代码。
这部分完整代码可以看我的github地址:点这里,点这里,点这里