token的使用
token官网: https://jwt.io/
token概念
token 令牌:
JWT: JSON Web Token 是一种标准
java-jwt 框架 是java实现的JWT标准的一个框架
JWT标准: token由三部分组成,每部分之间使用'.'分开
第一部分: 头(header)
里面保存了该token的加密方式
第二部分: 负载(payload)
里面保存了用户信息/token的信息(id/过期时间等等)
第三部分: 校验信息
第一部分和第二部分是JSON格式的数据使用Base64编码后的信息
注意: 该部分的信息是明文,不能存储敏感数据
具体代码如下:
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.lanou3g.tokendemo111.utils.JwtUtils;
import org.junit.Test;
import java.util.Date;
public class TokenTest {
// 自定义密钥,可以自己随便写,越复杂越好
public static final String SECRET_KEY = "53g2jkj2be215k1b1";
@Test
public void createToken() {
// 创建token
String token = JWT.create()
// 在负载中添加自定义的数据
.withClaim("userId", 1001)
.withClaim("username", "admin")
// 发布时间,也就是生成时间,可以稍微记录一下上次的登录时间
.withIssuedAt(new Date())
// 设置该token的过期时间
// 10秒钟后该token过期
.withExpiresAt(new Date(System.currentTimeMillis() + 100000))
// sign要在最后调用,使用Algorithm选择加密方式,常用HMAC256
.sign(Algorithm.HMAC256(SECRET_KEY));
System.out.println(token);
// 生成后的token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1NDEwNDEzNDksInVzZXJJZCI6MTAwMSwiaWF0IjoxNTQxMDQxMzM5LCJ1c2VybmFtZSI6Imt0bG42NjYifQ.tU_kElllOPZq4A67VEJCODlwD3OFi6ntC4V8ARO60Q0
}
@Test
public void require() {
// 根据校验规则HMAC256生成校验对象
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(SECRET_KEY)).build();
try {
// 校验前端发送过来的token是否合法
// 如果合法会返回一个解码后的jwt对象
// 如果不合法,会抛出xxx异常
// verify参数填写上面方法生成的token
DecodedJWT jwt = verifier.verify("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1NDEwNDMzNzcsInVzZXJJZCI6MTAwMSwiaWF0IjoxNTQxMDQzMjc3LCJ1c2VybmFtZSI6Imt0bG42NjYifQ.fCFxLol9V_a0DBdxi63jgtC2_6s2C81l9CpXd0oN85s");
System.out.println(jwt.getHeader());
System.out.println(jwt.getPayload());
} catch (TokenExpiredException e) {
System.out.println("Token已经过期");
} catch (SignatureVerificationException e) {
System.out.println("Token不合法");
} catch (Exception e) {
System.out.println("认证失败");
}
}
}
下面我们来模拟一下如果token到期时间高于80%,就返回给他一个新的token,代码如下:
新建一个工具类:
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import java.util.Date;
public class JwtUtils {
/**
* 默认过期时间30分钟
*
* @param userId 用户ID
* @return token
*/
public static String newToken(Long userId) {
// 为一个用户设置token并设置默认到期时间
return newToken(userId, Constants.DEFAULT_EXPIRED_SECONDS);
}
/**
* @param userId 用户ID
* @param expiredSeconds 过期时长
* @return token
*/
public static String newToken(Long userId, long expiredSeconds) {
return JWT.create()
.withClaim("userId", userId)
// 发布时间
.withIssuedAt(new Date())
// 到期时间
.withExpiresAt(new Date(System.currentTimeMillis() + expiredSeconds * 1000))
// 选择加密方式
.sign(Algorithm.HMAC256(Constants.SECRET_KEY));
}
/**
* 校验token是否合法
*
* @param token 需要校验的token
* @return 是否合法
*/
public static boolean checkToken(String token) {
// 根据校验规则HMAC256生成校验对象
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(Constants.SECRET_KEY)).build();
try {
// 校验token是否合法
verifier.verify(token);
return true;
} catch (JWTVerificationException e) {
e.printStackTrace();
return false;
}
}
/**
* 刷新token
*
* @param token 原token
* @return 新token
*/
public static String refreshToken(String token) {
// 进行Base64解码
DecodedJWT jwt = JWT.decode(token);
// 获得解码后token里的负载中的用户ID
Long userId = jwt.getClaim("userId").asLong();
// 调用上面的创建token的方法创建新的token
return newToken(userId);
}
/**
* token到期时间高于80%,就返回给他一个新的token,并做校验
* @param token
* @return
*/
public static String autoRequire(String token) {
// 校验token
boolean check = checkToken(token);
if (check) {
// 解码
DecodedJWT jwt = JWT.decode(token);
// 计算时间是否超过80%
long current = System.currentTimeMillis() / 1000;
// 获取开始时间
Long start = jwt.getClaim("iat").asLong();
// 获取结束时间
Long end = jwt.getClaim("exp").asLong();
if ((current - start) * 1.0 / (end - start) > 0.8) {
// 时间超过80%返回新的token
return refreshToken(token);
} else {
// 返回原来的token
return token;
}
} else {
throw new JWTVerificationException("token不合法");
}
}
}
回到之前的测试类:
附加: gethub 源码地址: https://github.com/JianJieMing/JianJieMing_JAVA/tree/master/token-demo-11-1
源码上有个基于token模拟用户登录的demo,token到期无法访问指定页面(附加拦截器,异常处理)