什么是 jwt?
JWT(JSON WEB Token)是一种开放的标准(RFC 7519),用于在网络应用间传递消息的一种方式。它是一种基于 JSON 的安全令牌,用于在客户端和服务端之间传输信息。官网地址
JWT由三部分组成,它们通过点 ·
进行分隔:
- Header(头部):包含了;令牌的类型和使用的加密算法等信息。通常采用 Base64 编码表示。
- Payload(负载):包含了身份验证和授权等信息,如用户ID、角色、权限等,也可以自定义其他信息、同样采用 Base64 编码表示。
- Signature(签名):使用指定的密钥对头部和负载进行签名,以确保令牌的完整性和真实性。
JWT 的工作流程如下:
- 用户提供有效的凭证(例如用户名和密码)进行身份验证。
- 服务器验证凭证,并生成一个 JWT 作为响应。JWT 包含了用户的身份信息和其他必要的数据。
- 服务器将 JWT 发送给客户端。
- 客户端在后续的请求中,将 JWT 放入请求的头部或其他适当的位置。
- 服务器在接收到请求后,验证 JWT 的签名以确保其完整性和真实性。如果验证通过,服务器使用 JWT 中的信息进行授权和身份验证。
依赖安装
passport
:一个流行的用于身份验证和授权的Node.js库。passport-jwt
:是passport库的一个插件,用于支持使用 JSON WEB Token(JWT)进行身份验证和授权。jsonwentoken
:生成 Token 的库。
npm i passport passport-jwt jsonwebtoken
代码编写
src/jwt/index.ts
import { injectable } from "inversify";
import passport from "passport";
import jsonwebtoken from "jsonwebtoken";
import { Strategy, ExtractJwt } from "passport-jwt";
@injectable()
export class JWT {
private secret: string = "fishcat should be happy!";
private opts = {
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), // 从请求头中获取token
secretOrKey: this.secret, // 密钥
};
constructor() {
this.strategy(); // 初始化jwt策略
}
/* 初始化jwt */
public strategy() {
const strate = new Strategy(this.opts, (jwtPayload, done) => {
// 验证token 自定义逻辑
if (jwtPayload) {
console.log('jwtPayload', jwtPayload)
return done(null, jwtPayload); // 验证成功,返回用户信息
} else {
return done(null, false); // 验证失败,返回false
}
});
// passport-jwt只是一个插件,不能直接使用,需要通过passport.use()方法注册到passport中
passport.use(strate);
}
static middleware() {
return passport.authenticate("jwt", { session: false }); // 不使用session
}
/* 创建token */
public createToken(data: object) {
return jsonwebtoken.sign(data, this.secret, { expiresIn: "7d" }) // 7天过期 1h 一小时
}
/* 初始化passport中间件 */
public init() {
return passport.initialize();
}
}
services.ts
import { injectable, inject } from "inversify";
import { JWT } from "../jwt";
@injectable()
export class TokenService {
constructor(@inject(JWT) private readonly jwt: JWT) { }
public async createToken(user: object) {
return this.jwt.createToken(user); // 创建token
}
}
controller.ts
/* 控制层,不做具体功能实现 */
import { controller, httpGet as Get, httpPost } from "inversify-express-utils";
import { UserService, TokenService } from "./services"; // 引入服务层,它也可以当做一个类型
import { inject } from "inversify";
import type { Request, Response } from "express";
import { JWT } from "../jwt";
// 控制器,它是一个装饰器,接收一个路径参数
@controller("/user")
export class User {
/**
* @inject(UserService) 装饰器,提供依赖注入
* private readonly 私有的 不可更改的
* userService: UserService 依赖的服务名称及其类型
* userService 左边的是修饰器的参数,右边是类型
*/
constructor(@inject(UserService) private readonly userService: UserService) {
// 这里可以做一些初始化操作,比如注入服务
}
// 修饰器中的第二个参数使用中间件鉴权 如果没有传 token 就会401
@Get("/list", JWT.middleware())
public async getIndex(req: Request, res: Response) {
const data = await this.userService.getUserList(); // 调用服务层的方法
// 做了鉴权之后,可以从 req.user 直接获取 token 包含的信息
res.json({ data, info: req.user }) // 返回数据
}
@httpPost("/add")
public async createUser(req: Request, res: Response) {
const data = await this.userService.addUser(req.body);
res.json({ data })
}
}
@controller("/getToken")
export class Token {
constructor(@inject(TokenService) private readonly token: TokenService) { }
@Get("/")
public async createToken(req: Request, res: Response) {
const token = await this.token.createToken({ name: "fishcat", code: "0221418512" });
res.json({ token, params: req.params })
}
}
main.ts
// 引入 reflect-metadata 以支持装饰器,必须顶层
import "reflect-metadata";
import express from "express";
import { InversifyExpressServer } from "inversify-express-utils";
import { Container } from "inversify";
import { JWT } from "./src/jwt"; // 引入 jwt 模块
import { TokenService } from "./src/user/services";
// 创建一个 Inversify 容器
const container = new Container();
/**
* jwt模块 注入容器
*/
container.bind(JWT).toSelf(); // 绑定 JWT 模块"
container.bind(TokenService).toSelf(); // 绑定 TokenService 服务
// 创建一个 InversifyExpressServer 实例,传入容器
const server = new InversifyExpressServer(container);
// 设置中间件
server.setConfig((app) => {
app.use(express.json()); // 解析 JSON 请求体
app.use(container.get(JWT).init()); // 关联 express
});
// 创建服务
const app = server.build();
app.listen(3000, () => {
console.log("Server is running on http://localhost:3000");
});
不传 token,返回结果 401,校验不通过
传入 token,结果正常响应。
参考:
https://xiaoman.blog.csdn.net/article/details/136312225