JWT
JSON Web Token
https://jwt.io/
应用场景
JWT是一种基于JSON的令牌安全验证(在某些特定的场合可以替代Session或者Cookie),一次生成随处校验
JWT组成
头部信息(header)
作用:指定该JWT使用的签名
{
“alg”: “HS256”// 签名算法 默认为HS256
}
将上面的json,用Base64URL 算法转成字符串,即为header。json
消息体playload
也就是负载的信息
{
"exp" (expiration time):过期时间
"sub" (subject):主题,一般用用户id,用来标识用户会话
"iat" (Issued At):签发时间
}
这个 JSON 对象也要使用 Base64URL 算法转成字符串。
作用:JWT的请求数据
签名( signature)
Signature 部分是对前两部分的签名,防止数据篡改。
需要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户。然后,使用 Header 里面指定的签名算法(默认是 HMAC SHA256),按照下面的公式产生签名。
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload),secret) header.payload.signature
头部、声明、签名用 . 号
最终:把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用"点"(.)分隔连在一起就得到了我们要的JWT
实现
依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--JWT-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.7.0</version>
</dependency>
</dependencies>
JwtUtil
public class JwtUtil {
/**
* 密钥,仅服务端存储
*/
private static String secret = "ko346134h_we]rg3in_yip1!";
/**
*
* @param subject 消息体
* @param issueDate 签发时间
* @return
*/
public static String createToken(String subject, Date issueDate) {
Calendar c = Calendar.getInstance();
c.setTime(issueDate);
c.add(Calendar.DAY_OF_MONTH, 20);
String compactJws = Jwts.builder()
.setSubject(subject)
.setIssuedAt(issueDate)
.setExpiration(c.getTime())
//签名算法 默认为HS256
.signWith(io.jsonwebtoken.SignatureAlgorithm.HS512, secret)
.compact();
return compactJws;
}
/**
* 解密 jwt
* @param token
* @return 消息体
* @throws Exception
*/
public static String parseToken(String token) {
try {
Claims claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
if (claims != null){
return claims.getSubject();
}
}catch (ExpiredJwtException e){
e.printStackTrace();
System.out.println("jwt过期了");
}
return "";
}
}
Filter校验
@WebFilter(urlPatterns = "/**")
@Component
public class MyFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
String token = req.getHeader("token");
if (StringUtils.isEmpty(token)) {
System.err.println("没有登陆");
} else {
//自动续期 手动续期
String parseToken = JwtUtil.parseToken(token);
if (StringUtils.isEmpty(parseToken)) {
System.out.println("请进");
chain.doFilter(request, response);
}
}
}
}
测试
public class JwtTest {
public static void main(String[] args) {
String token = JwtUtil.createToken("userId=1,role=admin", new Date());
System.out.println("token:" + token);
String[] split = token.split("\\.");
System.out.println("头部信息:" + new String(Base64.getDecoder().decode(split[0])));
System.out.println("消息体:" + new String(Base64.getDecoder().decode(split[1])));
String s = parseToken(token);
System.out.println("解码后信息:" + s);
try {
parseToken(token+"1");
}catch (JwtException e){
//错误token
e.printStackTrace();
}
}
}
输出
token:eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ1c2VySWQ9MSxyb2xlPWFkbWluIiwiaWF0IjoxNjIzMjI1MTc5LCJleHAiOjE2MjQ5NTMxNzl9.NFSWs4GovUDOIrrY9-66DmSiR7jLzP65vpwGR1biMuSX4WsGBlPMG7Vj-YZZOcKMggzmb0yl5e77fchEU5QGQA
头部信息:{"alg":"HS512"}
消息体:{"sub":"userId=1,role=admin","iat":1623225179,"exp":1624953179}
解码后信息:userId=1,role=admin
io.jsonwebtoken.SignatureException: JWT signature does not match locally computed signature. JWT validity cannot be asserted and should not be trusted.
at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:354)
at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:481)
at io.jsonwebtoken.impl.DefaultJwtParser.parseClaimsJws(DefaultJwtParser.java:541)
at com.example.jwt.JwtUtil.parseToken(JwtUtil.java:56)
at com.example.jwt.JwtTest.main(JwtTest.java:27)