什么是JWT?
JWT全称是JSON Web Token是一个开放标准(RFC 7519),目前最流行的跨域身份验证解决方案。
它定义了一种经过加密的格式,放在json对象在请求中传递,用于验证请求是否被允许访问。
JWT的原理
服务器经过认证以后,会生成加密串返回前台,结构如下图:
JSON Web Token由三部分组成,它们之间用.连接。
* Header 头部
* Payload 负载
* Signature 签名
Header
Header 部分用Base64URL解密后是一个JSON对象,主要描述了签名的算法和令牌类型。
{
"alg": "HS256",
"typ": "JWT"
}
alg属性表示签名使用的算法,默认为HMAC SHA256(写为HS256),typ属性表示令牌的类型,JWT令牌统一写为JWT。
Payload
Payload 部分同样也是一个JSON对象,它包含Claim。
Claim中存的就是这些字段,有三种类型:
JWT 规定了7个Registered claims
/**
* 从payload中拿到Claim
*
* @param token
* @return
*/
public Claims getClaimsFromToken(String token) {
Claims claims = Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody();
return claims;
}
需要注意的是JWT的信息默认是不加密的,Payload传递的不要有秘密信息。
Signature
Signature 部分是对前两部分的签名,用来防止数据篡改。
服务端指定密钥(secret),使用Header指定的签名算法,用转码后的JWT串产生签名。
在项目中使用了用 jjwt 生成:
String generateToken(Map<String, Object> claims) {
return Jwts.builder()
.setClaims(claims)
.setExpiration(generateExpirationDate(claims.get(CLAIM_KEY_USERNAME)))
.signWith(SignatureAlgorithm.HS512, secret)
.compact();
}
Base64URL
Base64URL 是一种能够对 URL 进行 base64 串型化的算法。
在目前项目中的外部接入管理里,需要将 url 放入到 Payload 中,如果直接使用的 Base64 算法,会与特殊符号+、/和=冲突,Base64URL会将 =省略、+替换成-,/替换成_。
JWT使用方式
客户端收到服务器返回的 JWT,需要自己存储在 Cookie 或者 localStorage中。
此后的每一次请求都必须带上这个 JWT,放在 cookie 中是无法跨域的,所以我们需要在 HTTP 请求的头信息或者参数中带上。
JWT的特点与session的差异
首先要明确,http协议是无状态的,每次请求对服务端而言,是不清楚上一次请求的认证。
session 的做法是将已经认证过的用户信息存储在服务器,用户下次请求带上 Session ID,服务器依此判断用户是否认证过。
因此也带来了一些问题:
与之相反的是 JWT 这种令牌认证方式,基于Token的身份认证是无状态的,服务器或者Session中不会存储任何用户信息,方便无状态的服务扩展,尤其适合做单点登录和手机端的鉴权。
但JWT也有不足,令牌一旦发出,是无法作废的,到期之前一直有效。