header(头)、 payload(载体)、 signature(签名)。

​HS256​​、​​RSA​​等等,​​typ=JWT​​为固定值,表示token的类型。。

{
"typ": "JWT",
"alg": "HS256"
}

载体

​iss​​ (发行者), ​​exp​​ (过期时间), ​​sub​​(用户信息), ​​aud​

{
"iat": 1493090001,
"name": "张三"
}
iss:Issuer,发行者
sub:Subject,主题
aud:Audience,观众
exp:Expiration time,过期时间
nbf:Not before
iat:Issued at,发行时间
jti:JWT ID

签名

JWT第二部分是signature,这部分的内容是这样计算得来的:

​Base64(header)​​.​​Base64(payload)​​得到一个Base64编码的字符串(下文成EncodeString)

HS256(EncodeString,"秘钥");计算得到的即使签名。

计算得到上面三部分内容后,用.连接起来就是一个完整的 JWT TOKEN,秘钥是保存在服务器上的一个私有密钥。

将头部、声明、签名用.号连在一起就得到了我们要的JWT。

eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MTUyOTgxNDEsImtleSI6InZhdWxlIn0.orewTmil7YmIXKILHwFnw3Bq1Ox4maXEzp0NC5LRaFQ

和Session方式存储id的差异

Session方式存储用户id的最大弊病在于要占用大量服务器内存,对于较大型应用而言可能还要保存许多的状态。一般而言,大型应用还需要借助一些KV数据库和一系列缓存机制来实现Session的存储。

而JWT方式将用户状态分散到了客户端中,可以明显减轻服务端的内存压力。除了用户id之外,还可以存储其他的和用户相关的信息,例如用户角色,用户性别等。

java 使用 jwt

引入jar

<!--JWT-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>

demo

package user;

import io.jsonwebtoken.*;
import org.joda.time.DateTime;
import org.junit.Test;

import java.util.Date;

public class JWT {
private static final String PRIVATE_KEY = "123456789";

@Test
public void jwtTest() throws InterruptedException {
// 设置3秒后过期
String jwt = this.buildJwt(DateTime.now().plusSeconds(3).toDate());
System.out.println(jwt);
// 验证token是否可用
boolean isOk = this.isJwtValid(jwt);
System.out.println(isOk);
}

public String buildJwt(Date exp) {
String jwt = Jwts.builder()
.signWith(SignatureAlgorithm.HS256, PRIVATE_KEY)//SECRET_KEY是加密算法对应的密钥,这里使用额是HS256加密算法
.setExpiration(exp)//expTime是过期时间
.claim("key", "vaule")//该方法是在JWT中加入值为vaule的key字段
.compact();
return jwt;
}

public boolean isJwtValid(String jwt) {
try {
//解析JWT字符串中的数据,并进行最基础的验证
Claims claims = Jwts.parser()
.setSigningKey(PRIVATE_KEY)//SECRET_KEY是加密算法对应的密钥,jjwt可以自动判断机密算法
.parseClaimsJws(jwt)//jwt是JWT字符串
.getBody();
String vaule = claims.get("key", String.class);//获取自定义字段key
//判断自定义字段是否正确
if ("vaule".equals(vaule)) {
return true;
} else {
return false;
}
}
//在解析JWT字符串时,如果密钥不正确,将会解析失败,抛出SignatureException异常,说明该JWT字符串是伪造的
//在解析JWT字符串时,如果‘过期时间字段’已经早于当前时间,将会抛出ExpiredJwtException异常,说明本次请求已经失效
catch (SignatureException | ExpiredJwtException e) {
return false;
}
}
}