JSON Web Token

29 3月

PC时代用cookie-session进行用户登录鉴权,但它有两个问题:

  1. cookie里存的仅仅是sessionid,而不是内含用户信息的session本身。服务端要根据sessionid查询保存在db里的session,这在分布式存储时不太方便
  2. app或小程序没有cookie

进入到移动互联网后,采用token进行用户登录鉴权,token里本身就带有用户信息,不存在服务端分布式存储session查询不便的问题。只要http请求header里带上token就行,不需要cookie。

JWT是目前使用最广泛的token生成方式,数据格式:Header.Payload.Signature,大概长这样:

yJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoienhsIiwiaWF0IjoxNjE3MDA2NzI1LCJleHAiOjE2MTcwOTMxMjV9.d-1qgslfaRTRmrwABRCmYHA21qcMN46yPnUzBAbxDHc

Header

用于描述元数据

{
 "typ": "JWT",  // type类型
 "alg": "HS256" // 签名的算法(algorithm),默认HS256(HMAC SHA256)
}

Payload

存放要加密的数据

{
 "sub": "1234567890",                           // 官方字段:subject,JWT的内容主题,大小写敏感的字符串或者URI
 "iss": "John Doe",                             // 官方字段:issuer,JWT的签发者,大小写敏感的字符串或者URI
 "aud": "xxx.com",                              // 官方字段:audience,JWT的接收者,大小写敏感的字符串或者URI
 "jti": "89c6f361-8935-4909-ae14-7acdf03d5e28", // 官方字段:JWT ID,JWT的唯一标识。用于区分内容相似的 JWTs,保证唯一性。
 "iat": 1617010254,                             // 官方字段:issued at (time),JWT的签发时间
 "nbf": 1617011654,                             // 官方字段:not before (time),JWT的生效时间
 "exp": 1617013854,                             // 官方字段:expiration (time),JWT的失效时间
 ... // 更多自定义字段,如openId,uuid等
}

Signature

用于对Header,Payload加上签名,防止数据篡改。

施加签名之前,会先对Header,Payload的JSON串型化后,需要用Base64URL加密(Base64URL和Base64差不多,但为了处理url,所以会对个别字符进行特殊处理)。

// encode
function b64(str) { 
  return new Buffer(str).toString('base64')
    .replace(/=/g, '')
    .replace(/\+/g, '-')
    .replace(/\//g, '_');
}

function encode(h, p) {
  const headerEnc = b64(JSON.stringify(h));
  const payloadEnc = b64(JSON.stringify(p));
  return `${headerEnc}.${payloadEnc}`;
}

// decode
function decode(jwt) {
  const [headerB64, payloadB64] = jwt.split('.');
  const headerStr = new Buffer(headerB64, 'base64').toString();
  const payloadStr = new Buffer(payloadB64, 'base64').toString();
  return { header: JSON.parse(headerStr), payload: JSON.parse(payloadStr) }; 
}

然后对Base64URL加密后的Header,Payload,用指定的算法施加签名:

实际项目中会使用jsonwebtoken,封装了上面base64加解密和施加签名的动作,使用起来很方便。

Token交互

生成的JWT通常放在cookie或localStorage里。在cookie里可能会遇到跨域问题,也可以加在请求头Authorization字段里:

Authorization: Bearer <token>

注意事项和传统token注意事项相同:

  • JWT推荐要加密,如果不加密,不要放置敏感信息
  • 最好使用https协议进行传输,减少盗用
  • JWT一旦签发,在到期前都会始终有效,所以要合理设置有效期

发表评论

邮箱地址不会被公开。 必填项已用*标注