Skip to content

Nest中实现Session与JWT

Nest中实现Session与JWT#

创建项目:

Terminal window
nest n nest-session-jwt -g -p pnpm

安装express-session

pnpm add express-session @types/express-session

启用session:

import { NestFactory } from '@nestjs/core'
import { AppModule } from './app.module'
import session from 'express-session'
async function bootstrap() {
const app = await NestFactory.create(AppModule)
app.use(
session({
secret: 'my-secret',
resave: false,
saveUninitialized: false,
})
)
await app.listen(process.env.PORT ?? 3000)
}
bootstrap()

在controller中测试一下:

import { Controller, Get, Req, Session } from '@nestjs/common'
import { AppService } from './app.service'
import { Request } from 'express'
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get()
getHello(): string {
return this.appService.getHello()
}
@Get('session1')
getSession(@Session() session: Record<string, any>) {
console.log(session)
session.views = session.views ? session.views + 1 : 1
return session.views
}
@Get('session2')
getSession2(@Req() req: Request) {
const session = req.session
console.log(session)
session.views = session.views ? session.views + 1 : 1
return session.views
}
}

上面用了两种方式获取Session,随便哪种都可以,只是下面的方式TS我处理的更加细节一些,如果这样的话,需要扩充session的类型声明,可以自己在src下创建types文件夹,创建相关的.d.ts文件,比如express-session.d.ts

/* eslint-disable @typescript-eslint/no-unused-vars */
import { Session } from 'express-session'
declare module 'express-session' {
// 通过扩展 Session 类来修改 SessionData
interface SessionData {
user: {
username: string
role: string
}
views: number
}
}

引入Session类是因为SessionData本身其实是 Session 类中的一个接口,所以如果你要扩展 SessionData,你需要引用它所依赖的 Session 类,或者正确地声明 SessionData,才能确保 TypeScript 正确地推断出它的类型

接下来是JWT,JWT需要引入@nestjs/jwt

Terminal window
pnpm add @nestjs/jwt

然后在App模块中引入JWT

import { Module } from '@nestjs/common'
import { AppController } from './app.controller'
import { AppService } from './app.service'
import { JwtModule } from '@nestjs/jwt'
@Module({
imports: [
JwtModule.register({
secret: 'secretKey',
signOptions: { expiresIn: '7d' },
}),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}

简单指定secret密钥和过期时间,然后在controller中注入JwtService

import {
Controller,
Get,
Headers,
Inject,
Req,
Res,
Session,
UnauthorizedException,
} from '@nestjs/common'
import { AppService } from './app.service'
import { Request, Response } from 'express'
import { JwtService } from '@nestjs/jwt'
@Controller()
export class AppController {
@Inject()
private jwtService: JwtService
constructor(private readonly appService: AppService) {}
@Get('jwt1')
getJwt1(@Res({ passthrough: true }) res: Response) {
const token = this.jwtService.sign({ count: 1 })
res.setHeader('Authorization', `Bearer ${token}`)
return 'hello jwt1'
}
@Get('jwt2')
getJwt2(
@Headers('authorization') authorization: string,
@Res({ passthrough: true }) res: Response
) {
console.log(authorization)
if (authorization) {
try {
const token = authorization.split(' ')[1]
const payload = this.jwtService.verify(token)
const newToken = this.jwtService.sign({ count: payload.count + 1 })
res.setHeader('Authorization', `Bearer ${newToken}`)
} catch (e) {
console.log(e)
throw new UnauthorizedException()
}
} else {
throw new UnauthorizedException()
}
return 'hello jwt2'
}
}

在Authorization头信息前面加上Bearer,主要是OAuth 2.0 规范(RFC 6750)明确规定了 使用 Bearer 作为令牌类型