JWT简介
官网地址 https://jwt.io
JWT是JSON WEB TOKEN的缩写,它是基于 RFC 7519 标准定义的一种可以安全传输的的JSON对象,由于使用了数字签名,所以是可信任和安全的。
从分布式认证流程中,我们不难发现,这中间起最关键作用的就是token,token的安全与否,直接关系到系统的健壮性,使用JWT来实现token的生成和校验。可以生成token,也可以解析检验token。
JWT的组成 header.payload.signature
- JWT token的格式:header.payload.signature(头部.荷载.签名)
- header中用于存放签名的生成算法;
{
"alg": "HS256",
"typ": "JWT"
}
- payload中用于存放数据,比如过期时间、用户名、用户所拥有的权限等;
载荷:是实际的用户数据以及其他自定义数据比如用户名,用户角色,过期时间等,但是不要放密码,会泄露!
载荷是token中存放有效信息的部分,进行 Base64 编码形成 JWT 的第二部分。
{
"exp": 1572682831,
"user_name": "admin",
"authorities": [
"admin"
],
"jti": "c1a0645a-28b5-4468-b4c7-9623131853af",
"client_id": "client01",
"scope": [
"all"
]
}
-
signature是以header和payload生成的签名,一旦header和payload被篡改,验证将失败。
签名:将标头+载荷分别采用base64编码后,用“.”相连,再加入盐,最后使用头部声明的编码类型进行编码,就得到了签名。通过前面两部分标头+载荷+私钥再配合指定的算法,生成用于校验 JWT 是否有效的特殊字符串。签名的生成规则如下。
HMACSHA256(base64UrlEncode(header) + “.” + base64UrlEncode(payload), secret)
JWT实例
这是一个JWT的字符串,可以在该网站上获得解析结果:https://jwt.io/
eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIiLCJwaG9uZSI6IjEzNTUxNDk0MTk2IiwiaXNzIjoiV2VkIEphbiAyNCAxNDoyNDoyMSBDU1QgMjAyNCIsImV4cCI6MTcwODY2OTQ2MSwidXNlcklkIjoxLCJ1c2VybmFtZSI6ImFkbWluIn0.n_Zos_XyB02ld9HbLjf8v4uQF7HU5LEJ7sO13mEROImTVhMy2gMo60pEtt2SP5N0mSTskl_pCsWB3tx7SvfzhQ
JWT和token的区别
- token需要查库验证token 是否有效
- JWT不用查库或者少查库,直接在服务端进行校验。因为用户的信息及加密信息在第二部分payload和第三部分签证中已经生成,只要在服务端进行校验就行,并且校验也是JWT自己实现的。
完
其他
public boolean verifyToken(String token) {
try {
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(secret)).withIssuer(ISSUER).build();
jwtVerifier.verify(token);
return true;
} catch (TokenExpiredException e) {
log.error("Token已过期: {} " ,e.getMessage());
throw new BusinessException(CommonExceptionEnum.GL10010010.getCode(),CommonExceptionEnum.GL10010010.getMsg());
} catch (UnsupportedJwtException e) {
log.error("Token格式错误: {} " ,e.getMessage());
throw new BusinessException(CommonExceptionEnum.GL10010002.getMsg());
} catch (JWTDecodeException e) {
log.error("Token没有被正确构造: {} " ,e.getMessage());
throw new BusinessException(CommonExceptionEnum.GL10010003.getMsg());
} catch (SignatureException e) {
log.error("签名失败: {} " ,e.getMessage());
throw new BusinessException(CommonExceptionEnum.GL10010004.getMsg());
} catch (Exception ex){
ex.printStackTrace();
throw new BusinessException(ex.getMessage());
}
}