闽公网安备 35020302035485号
其中,Header 和 Payload 都是 JSON 对象,Signature 是 Header 和 Payload 的签名,用于验证 Token 的完整性。
{
"alg": "HS256",
"typ": "JWT"
}
export interface JWTHeader {
alg: string;
typ: string;
}
Payload{
"userId": "1234567890",
"username": "admin",
"write": true,
"exp": 1516239022
}
export interface JWTPayload {
userId: string; # 用户ID
username: string; # 用户名
write?: boolean; # 管理界面权限
exp?: number; # 过期时间(暂未用到)
}
Signaturefunction sign(payload: JWTPayload, secret: string): string {
const header = { alg: "HS256", typ: "JWT" };
const headerString = JSON.stringify(header);
const payloadString = JSON.stringify(payload);
const signatureString = crypto
.createHmac("sha256", secret)
.update(`${headerString}.${payloadString}`)
.digest("hex");
// 使用 `.` 拼接三个部分,这就是一个完整的 JSON Web Token
return `${headerString}.${payloadString}.${signatureString}`;
}
验证 Tokenfunction verify(token: string, secret: string): JWTPayload {
const parts = token.split(".");
const header = JSON.parse(Buffer.from(parts[0], "base64").toString());
const payload = JSON.parse(Buffer.from(parts[1], "base64").toString());
const signatureString = parts[2];
// 验证算法
if (header.alg !== "HS256") {
throw new Error("无效算法");
}
// 验证签名
// 通过对解析后的 header 和 payload 再次进行签名,比对两个签名是否一致
const signature = crypto
.createHmac("sha256", secret)
.update(`${parts[0]}.${parts[1]}`)
.digest("hex");
if (signature !== signatureString) {
throw new Error("无效签名");
}
// 验证过期时间
if (payload.exp && payload.exp < Date.now()) {
throw new Error("身份认证已过期");
}
return payload;
}
认证流程注意:Token 只应该包含可用与验证用户身份的信息,千万不要包含诸如密码之类的敏感信息,因为 Token 并不是加密的,在浏览器中使用函数 atob(token.split('.')[1]) 即可解析到 payload 对象的完整内容。
客户端每次请求都会自动带上 Cookie,服务端可以通过验证 Cookie 中 Token 的有效性来判断用户的身份。
如果验证通过,则继续返回用户需要的资源。
if (!payload.write) {
// 处理没有权限的情况
}
常见问题