jwt(json web token)入门,node实现简单jwt

119 阅读2分钟
jwt(json web token)入门,node实现简单jwt
// 全部代码
const mycrypto = require("node:crypto");

const sign = (data, secret) => {
const header = {"alg": "sha256", "type": "jwt"};
const content = [
base64Encode(header),
base64Encode(data)
];
const signature = mycrypto.createHmac('sha256', secret)
.update(content.join("."), secret).digest('base64');
return fromBase64([...content, signature].join("."));
};

function toBase64(str){
    const newStr = str.replace("/_/g","/").replace("/-/g","+");
    const len = newStr.length;
    const padLen = len%4 ? (4 - (len%4)) : 0;
    return newStr + new Array(padLen).fill("=").join("");
}

function fromBase64(data){
    return data.replace("/\+/g","-")
    .replace("/\//g","_").replace("/=/g","");
}

function base64Encode(data){
    return Buffer.from(JSON.stringify(data))
    .toString("base64");
}

function verify(token, secret) {
    const [header, payload, signature] = token.split(".");
    const newSignature = mycrypto.createHmac("sha256", secret).update(
        [toBase64(header), toBase64(payload)].join('.')
    ).digest('base64');
    console.log(signature, newSignature);
    if(signature === fromBase64(newSignature)){
        return true;
    }
    return false;
}
const token = sign("acsa","xx")
console.log(verify(token, "xx"));

jwt是用来校验用户状态的工具

jwt解决的问题:

jwt放在url中或者header中不会有跨域问题,而且服务端不用保存会话数据,每次校验即可,而cookie在多个域名下会有跨域问题,sessionId放到cookie中时,服务端要存储sessionId,服务端分布式部署时要解决共享session问题

jwt的原理

登录时,服务端校验用户名和密码后,根据算法将用户标识生成token,返回前端,前端在后面的请求中携带token,后端进行鉴权

jwt的数据结构
  1. header {"alg":"SHA256", "type": "jwt"} alg(algorithm)是指使用的算法,
  2. payload 官方定义了7个字段,此外还可以自定义字段
  • iss(issue):签发人
  • exp:(expiration time):过期时间
  • sub(subject): 主题
  • aud(audience): 受众
  • nbf(not before): 生效时间
  • iat:(issue at): 签发时间
  • jti:(jwt id): 编号
  • 自定义 例如{"userId":123}
  1. signature 对前两部分进行签名
HMACSHA256(base64Encode(header)+"."+base64Encode(payload),secret);
  • secret是字符串加密的key
  • 生成的token是有可能放到url中的,而base64有3个字符+/=在url里面有特殊的含义,所以在转成base64时要把这三个字符替换一下,
  • "+" -> "-"
  • "=" -> ""
  • "/" -> "_"
function base64Encode(data){
return Buffer.from(JSON.stringify(data))
.toString("base64");
}
function fromBase64(data){
return data.replace("/\+/g","-")
.replace("/\//g","_").replace("/=/g","");
}
function toBase64(str){
const newStr = str.replace("/_/g","/").replace("/-/g","+");
const len = newStr.length;
const padLen = len%4 ? (4 - (len%4)) : 0;
return newStr + new Array(padLen).fill("=").join("");
}
实现原理

使用nodejs内置的cryto模块

const crypto = require("crypto");
const sign = (data, secret) => {
const header = {"alg": "sha256", "type": "jwt"};
const content = [
base64Encode(header),
base64Encode(data)
];
const signature = crypto.createHmac('sha256', secret)
.update(content.join("."), secret).digest('base64');
return fromBase64([...content, signature].join("."));
};

const verify = (token,secret) => (token, secret) {
    const [header, payload, signature] = token.split(".");
    const newSignature = mycrypto.createHmac("sha256", secret).update(
        [toBase64(header), toBase64(payload)].join('.')
    ).digest('base64');
    console.log(signature, newSignature);
    if(signature === fromBase64(newSignature)){
        return true;
    }
    return false;
}
jwt缺点

服务端不保存会话状态,所以jwt会在有效期内会一直有效,一旦泄露,任何人都可以获得jwt认证的权限,为了减少盗用jwt设置的有效时间不宜设置过长,重要操作一定要进行身份验证,建议使用https协议传输jwt