最近在学习神光大神的《Nest通关秘籍》,接下来的日子里,我将更新一系列的学习笔记。
感兴趣的可以关注我的专栏《Nest 通关秘籍》学习总结。
特别申明:本系列文章已经经过作者本人的允许。
大家也不要想着白嫖,此笔记只是个人学习记录,不是非常完善,如想深入学习可以去购买原版小册,购买链接点击《传送门》。
本章我们来学习一下如何在Nest中实现session和jwt鉴权。
1. 创建项目
首先用 @nest/cli 快速创建一个 Nest.js 项目
nest new jwt-and-session -p npm
2. session + cookie
的实现
安装 express-session 和它的 ts 类型定义:
pnpm install express-session @types/express-session
然后在入口模块里启用它:
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import * as session from 'express-session';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.use(
session({
secret: 'xiumubai',
resave: false,
saveUninitialized: false,
}),
);
await app.listen(3000);
}
bootstrap();
- 指定加密的密钥 secret。
- resave 为 true 是每次访问都会更新 session,不管有没有修改 session 的内容,而 false 是只有 session 内容变了才会去更新 session。
- saveUninitalized 设置为 true 是不管是否设置 session,都会初始化一个空的 session 对象。比如你没有登录的时候,也会初始化一个 session 对象,这个设置为 false 就好。
在 controller 里就可以注入 session 对象:
@Get('sss')
sss(@Session() session) {
console.log(session)
session.count = session.count ? session.count + 1 : 1;
return session.count;
}
在 session 里放了个 count 的变量,每次访问加一,然后返回这个 count。
运行项目:
npm run start:watch
然后用 apifox 测试下:
当每次发送一个请求的时候count都会+1.
而且返回了一个 cookie 是 connect.sid,这个就是对应 session 的 id。
因为 cookie 在请求的时候会自动带上,就可以实现请求的标识,给 http 请求加上状态。
3. jwt的实现
安装包:
pnpm install @nestjs/jwt
然后在 AppModule 里引入 JwtModule:
import { Module } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
imports: [
JwtModule.register({
secret: 'xiumubai',
signOptions: {
expiresIn: '7d',
},
}),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
指定 secret,也就是加密 jwt 的密钥,还有 token 过期时间 expiresIn,设置 7 天。
然后在 controller 里注入 JwtModule 里的 JwtService,然后添加一个handler方法:
import { Controller, Get, Inject, Session, Res } from '@nestjs/common';
import { AppService } from './app.service';
import { JwtService } from '@nestjs/jwt';
import { Response } from 'express';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Inject(JwtService)
private jwtService: JwtService;
@Get('ttt')
ttt(@Res({ passthrough: true }) response: Response) {
const newToken = this.jwtService.sign({
count: 1,
});
response.setHeader('authorization', 'bearer ' + newToken);
return 'hello';
}
}
这里使用 jwtService.sign
来生成一个 jwt token,放到 response header
里。
然后我们在apifox中访问一下看看:
可以看到,返回的响应确实带上了这个 header。
现在我们再加一些逻辑,如果后端接受请求的时候拿到了authorization
,那就把它取出来,然后 +1 之后再放回去:
import {
Controller,
Get,
Inject,
Session,
Res,
Headers,
UnauthorizedException,
} from '@nestjs/common';
import { AppService } from './app.service';
import { JwtService } from '@nestjs/jwt';
import { Response } from 'express';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Inject(JwtService)
private jwtService: JwtService;
@Get()
getHello(): string {
return this.appService.getHello();
}
@Get('ttt')
ttt(
@Headers('authorization') authorization: string,
@Res({ passthrough: true }) response: Response,
) {
if (authorization) {
try {
const token = authorization.split(' ')[1];
const data = this.jwtService.verify(token);
const newToken = this.jwtService.sign({
count: data.count + 1,
});
response.setHeader('authorization', 'bearer ' + newToken);
return data.count + 1;
} catch (e) {
console.log(e);
throw new UnauthorizedException();
}
} else {
const newToken = this.jwtService.sign({
count: 1,
});
response.setHeader('authorization', 'bearer ' + newToken);
return 1;
}
}
}
通过 @Headers 装饰器取出 autorization 的 header,然后通过 jwtService.verify 对它做验证。
如果验证失败,那就抛出 UnauthorizedException 异常,让 Nest 内置的 Exception Filter 来处理。
验证成功就重新生成 jwt 放到 header 里返回。
如果没有 autorization 的 header,那就生成一个 jwt 放到 header 里返回。
下面我们测试一下:
第一次访问:
响应为1,返回一个token,复制下来。
第二次访问:
请求头带着复制的token值
响应为2,然后返回了一个新的token。
第三次访问,重复1,2步骤。
这就是通过 jwt 保存状态的方式。
当然,一般正常开发中,前端会保存一个token,然后请求的时候传给后端,后端去校验这个token,如果没有问题,就会通过请求。如果有问题,就会重新登录,然后生成一个新的token。
如果这里我们传一个错误的token值:
这时候 jwtService.verify 方法就会抛异常,然后我们返回了 401 错误。
这样,我们就分别用 Nest 分别实现了 session + cookie 和 jwt 两种保存 http 状态的方式。