转载自:https://www.zuojl.com/jwt/
叙述
JSON Web Token(缩写 JWT)是目前最流行的跨域认证解决方案,本文介绍它的原理和用法。
应用程序或者客户端向服务器请求授权,授权服务器向客户端返回一个 JWT。之后将 JWT 放入到请求里(通常放在 HTTP 的 Authorization 头里)。服务器接收请求后,验证 JWT 并执行对应的逻辑。为了防止用户的信息被篡改,服务器在生成这个对象的时候,会加上签名。JWT 的大体结构如下
JWT 结构
JWT 有三部分组成,中间用(.)进行分割,JWT 是没有换行的。三个部分以次为Header(头部)、Payload(负载)、Signature(签名)。就如 JWT 网站 的示例一样
Header
Header 部分是将一个 Json 对象进行 Base64URL 算法之后的字符串。其中 alg
表示签名的算法(algorithm)为 HMAC SHA256(写成 HS256)。 typ
表示 token (令牌)的类型为 JWT
Payload
Payload 部分和 Header 一样是将 JSON 对象进行 Base64URL 转换。其中 JWT 规格的官方字段含义如下
- iss (issuer):签发人
- exp (expiration time):过期时间
- sub (subject):主题
- aud (audience):受众
- nbf (Not Before):生效时间
- iat (Issued At):签发时间
- jti (JWT ID):编号
除了官方的字段外,也是可以进行自定义字段的。
Signature
Signature 部分是对前两部分的签名,防止数据篡改。HS256 的算法如上图所示的
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret
)
jjwt 实现
首先引入依赖
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.7.0</version>
</dependency>
生成 JWT Token
// 生成 JWT Token
public static String generateToken(String payload) {
Date now = new Date();
Date expire = new Date(now.getTime() + 5 * 60 * 1000);
return Jwts.builder()
.setHeaderParam("typ", "JWT")
.setSubject(payload)
.setIssuedAt(now)
.setExpiration(expire)
.signWith(SignatureAlgorithm.HS256, SECRET_KEY)
.compact();
}
此处生成一个过期时间为 5 分钟的 Token
校验 Token
下面对是否合法和是否过期进行校验
// 解析 Token
private static Claims parseToken(String token) {
try {
return Jwts.parser()
.setSigningKey(SECRET_KEY)
.parseClaimsJws(token)
.getBody();
} catch (Exception e) {
return null;
}
}
// 校验 Token 是否合法
public static boolean isTokenValid(String token) {
return parseToken(token) != null;
}
// 校验 Token 是否过期/失效
public static boolean isTokenExpired(String token) {
Claims claims = parseToken(token);
return claims != null && claims.getExpiration().before(new Date());
}
更新 Token
对于 Token 应该在用户每次操作后都更新其过期时间,俗称喂狗。
// 更新 Token 的过期时间
public static String updateToken(String token) {
Claims claims = parseToken(token);
return claims == null ? null : generateToken(claims.getSubject());
}
JWT 的特点
- JWT 默认是不加密的,只是简单的进行 Base64URL 转换,所以不要存储敏感信息。
- 为了安全,JWT 应该使用 HTTPS 协议传输,避免使用 HTTP 明码进行传输。
- 由于服务器不保存 session 状态,因此一旦 JWT 签发后,无法在使用过程中对其进行废除和更改权限,在过期之前始终有效。