前言
上篇文章介绍了jwt的组成包括安全方面的理论知识(JWT(理论篇)),这篇文章以java为例实现jwt令牌的颁发和验证接口。
本文不会从手写jwt生成跟,而是使用现有的内库来实现(现在的web应用很少有纯手写的了,都是跟拼积木一样,一个个插件组装起来的)。
引入jwt内库
在jwt官网有对应各种语言的jwt库安装介绍以及支持的签名算法: https://jwt.io。
本文使用的是auth0这个库,在pom文件添加依赖:
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.8.1</version>
</dependency>
依赖安装好后接下来编写我们的第一个接口生成token:
颁发token接口
private static String getToken() {
Algorithm algorithm = Algorithm.HMAC256(secret); // 定义签名算法
Map<String,Date> map = JwtToken.calculateExpiredIssues(); // 定义过期时间
return JWT.create()
.withClaim("uid", 1) // 存放在payload中的用户id
.withClaim("nickname", "路过一只大侠") // 存放在payload中的用户昵称
.withExpiresAt(map.get("expiredTime")) // 设置过期时间
.withIssuedAt(map.get("now")) // 设置颁发时间
.sign(algorithm); // 使用上面定义的算法对payload、header签名生成token
}
-
第2行定义jwt签名使用的算法这里使用的,参数是你定义的秘钥这个秘钥不能泄漏。
-
第6行
withClaim
这个方法用来定义payload中的内容存放业务数据,这个由你自己定义想放什么就放什么。 -
第10行
sign
这个方法使用上面定义的算法对payload、header进行签名防止数据被篡改。 -
第8行
withExpiresAt
用来定义令牌的过期时间, auth0这个库设置过期时间需要手动去计算一个未来的时间点,什么是未来时间点? 比如颁发令牌的这一刻是 2014-8-13 10:00:00,
你想要2小时后过期你就需要手动的把两小时加上变成 2014-8-13 12:00:00, 这点相对其它的jwt内库有点笨,其它的库只要传入2小时就会自动帮你计算出过期时间。为了计算出过期时间我们在下面定义了
calculateExpiredIssues
方法,就是第二所调用的。
calculateExpiredIssues
// 反回当前时间加上过期时间后的时间
private static Map<String, Date> calculateExpiredIssues() {
Map<String, Date> map = new HashMap<>();
Calendar calendar = Calendar.getInstance();
Date now = calendar.getTime();
// 当前时间加上120分钟、两小时后过期
calendar.add(Calendar.MINUTE, 120);
map.put("now", now);
map.put("expiredTime", calendar.getTime());
return map;
}
校验token接口
这个接口返回布尔值,验证过true否则false。
public static boolean verifyToken(String token) {
DecodedJWT decodedJWT;
Algorithm algorithm = Algorithm.HMAC256(secret); // 定义签名算法
JWTVerifier jwtVerifier = JWT.require(algorithm).build();
try {
jwtVerifier.verify(token); // 比对数据签名是否一至
} catch (Exception e) {
return false;
}
return true;
}
-
第2行 定义了跟颁发token接口一样的签名算法用于对前端传过来的token进行签名,再进行比对。
-
第6行 通过auth0库内部的verify方法对签名进行对比,一至说明token没有被改过,这个方法内部还会对过期时间进行判断,只要是签名不一致或是token过期了都会抛出一个异常,我们对这个方法进行try/catch,一旦捕获到异常就反回false表示校验失败,不然就反回true表示校验成功令牌有效。
获取payload中的值
获取payload中的值只需对 verifyToken
方法进行简单修改即可:
public static Map<String, Claim> getClaims(String token) {
DecodedJWT decodedJWT;
Algorithm algorithm = Algorithm.HMAC256(secret);
JWTVerifier jwtVerifier = JWT.require(algorithm).build();
try {
decodedJWT = jwtVerifier.verify(token);
} catch (JWTVerificationException e) {
throw new ForbiddenException(10004);
}
return decodedJWT.getClaims();
}
auth0库内部的verify方法如果校验成功会返回一个 DecodedJWT 对象,这个对象下有个 getClaims 方法可以获取到包含payload数据的map对象。
测试
使用的postman进行测试:
getToken
verifyToken
上篇文章:(JWT(理论篇))
完!