Nest 使用 双 token 和单 token
双 token 和单 token 的
目的都是为了做到无感刷新.让用户感觉不到刷新,只是后台自动刷新了 token
双 token 是长换短 token,短 token 过期时间短,长 token 过期时间长,短 token 过期了,用长 token 换取短 token,长 token 过期了,重新登录
单 token 就是在守卫里面后台设置头部 token
双 token
流程就是 登录 接口 获取到 双 token 一个短 一个长
在出一个刷新接口,接口里面获取到 长 token 换取短 token,然后返回给前端,前端存起来,每次请求都带上短 token
如果长 token 过期了,重新登录
配置文件
dev.yml
bash
# jwt 配置 d代表天 h代表小时 m分钟 s代表秒
jwt:
secretkey: 'jsopy'
expiresin: '5s'
refreshExpiresIn: '2h'
其他环境相同
jwt.service.ts
ts
import { Injectable, Inject } from "@nestjs/common";
import { JwtService } from "@nestjs/jwt";
import { ConfigService } from "@nestjs/config";
@Injectable()
export class JwtServiceAll {
// 注入配置文件
@Inject()
private readonly configService: ConfigService;
constructor(private readonly jwtService: JwtService) {}
async setToken(userInfo: any) {
// 这里不能写用户密码,怕破译
const payload = {
sub: userInfo.id, // sub 就是用户名称
phonenum: userInfo.phonenum, // phonenum 就是手机号 换成你自己的
};
const result = await this.jwtService.sign(payload); // 设置短时间采取默认
// 生成token
return result;
}
verifyToken(token: string) {
return this.jwtService.verify(token, {
secret: this.configService.get("jwt").secretkey,
});
}
// refreshToken
async setRefreshToken(userInfo: any) {
const payload = {
sub: userInfo.id, // sub 就是用户名称
username: userInfo.username, // username 就是用户姓名
};
const result = await this.jwtService.sign(payload, {
expiresIn: this.configService.get("jwt").refreshExpiresIn, // 设置长时间
});
return result;
}
}
user.service.ts
ts
// 2. 测试jwt
async testjwt() {
// 这里需要验证下密码 我省略了
// 返回一个短token 一个长token 手机号换成你需要的字段
const accsee_token = await this.jwtService.setToken({
id: 1,
phonenum: '1234567890',
});
const refresh_token = await this.jwtService.setRefreshToken({
id: 1,
phonenum: '1234567890',
});
const result = {
accsee_token,
refresh_token,
};
return result;
}
user.controller.ts
一个登录的时候 会返回 两个 token
一个刷新的时候 会返回 两个 token
前端当 accsee_token 过期了,用 refresh_token 去刷新接口,刷新接口会返回两个 token,前端再存起来,每次请求都带上短 token
ts
@Post('testjwt')
async testjwt() {
const token = await this.userService.testjwt();
return {
data: {
token,
},
};
}
单 token
- 用的少
每次访问都自己刷新 token.前端存下来,每次请求都带上 token
修改 global.guard.ts
ts
import {
CanActivate,
ExecutionContext,
Inject,
Injectable,
} from "@nestjs/common";
import { Observable } from "rxjs";
import { GlobalGuardException } from "./globalguard.exception";
import { ConfigService } from "@nestjs/config";
import { JwtServiceAll } from "../modules/jwt/jwt.service";
@Injectable()
export class GlobalGuard implements CanActivate {
@Inject()
private configService: ConfigService;
@Inject()
private jwtService: JwtServiceAll;
async canActivate(context: ExecutionContext): Promise<boolean> {
//权限验证
const request = context.switchToHttp().getRequest();
// 白名单
const whiteList = this.configService.get("perm").router.whiteList;
// 验证
if (whiteList.includes(request.url)) {
return true;
} else {
// 判断
const authorization = request.header("Authorization") || "";
const bearer = authorization.split(" ");
if (!bearer || bearer.length < 2) {
const result = JSON.stringify([{ message: "请输入token" }]);
throw new GlobalGuardException(result);
}
const token = bearer[1];
try {
const info = this.jwtService.verifyToken(token);
// 我这里是解析出来后把userId赋值给request 这样控制器就拿到了
(request as any).userId = info.sub; // 换成你自己的payload对应字段
// 每次访问都刷新token
const response = context.switchToHttp().getResponse();
const newToken = await this.jwtService.setToken({
id: 1, // 内容换成你自己的
username: "张三", // 内容换成你自己的
});
// 设置了新的token
response.setHeader("Authorization", `Bearer ${newToken}`);
return true;
} catch (e) {
const result = JSON.stringify([{ message: "token 错误" }]);
throw new GlobalGuardException(result);
}
}
}
}
增加跨域
- main.ts
ts
import { NestFactory } from "@nestjs/core";
import { AppModule } from "./app.module";
// 改变端口 增加跨域
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.enableCors({
exposeHeaders: "Authorization", // 换成你自己给前端返回的字段名
});
await app.listen(process.env.PORT ?? 5000);
}
bootstrap();
前端
- axios 里面拦截器
ts
axios.interceptors.response.use((response) => {
const newToken = response.headers["Authorization"];
if (newToken) {
localStorage.setItem("Authorization ", newToken);
}
return response;
});