JWT笔记
JWT的结构
# 1 令牌组成
- 1.标头(Header)
- 2.有效载荷(Payload)
- 3.签名(Signature)
- 因此,JWT通常如下所示:xxxxx.yyyyy.zzzzz Header.Payload.Signature
# 2 Header
- 标头通常由两部分组成:令牌的类型和所使用的签名算法,例如HMAC SHA256或ESA,它会使用Base64编码组成 JWT 结构的第一部分
- 注意:Base64是一种编码,也就是说,它可以被翻译回原来的样子,它不是一种加密过程
{
"alg": "HS256",
"typ": "JWT"
}
# 3 Payload
- 令牌的第二部分是有效负载,其中包含声明,声明是有关实体和其他数据的声明.同样的,它会使用Base64编码组成 JWT 结构的第二部分
- 不要在Payload里放入敏感信息!!
{
"sub":"1234567890"
"name":"Lebron Jordan"
"admin": true
}
# 4 Signature
- 前面两部分是使用Base64进行编码的,即前端可以解开知道里面的信息, Signature 需要使用编码后的header和payload以及我们提供的一个密钥,然后使用header中指定的签名算法(Hs256)进行签名,签名的作用是保证JWT没有被篡改过
- 如 :
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload),secret);
# 签名目的
- 最后一步签名的过程,实际上是对头部以及负载内容进行签名,防止内容被篡改.如果有人对头部以及负载的内容解码之后进行修改,再进行编码,最后加上之前的签名组合形成的新的JWT,那么服务器会判断出新的头部和负载形成的签名和JWT附带上的签名是不一样的.如果要对新的头部和负载进行签名,在不知道服务器加密时使用的密钥的话,得出来的签名是不一样的.
# 信息安全问题
- Base64编码可逆,信息容易暴露
- 因此,在JWT中,不应该在负载里面加入任何敏感的信息.
# 5 放在一起
- 输出是三个由点分割的Base64-URL字符串,可以在HTML和HTTP环境中轻松传递这些字符串,与基于XML标准相比,它更紧凑.
- 简洁
- 可以通过URL,POST 参数或者在HTTP header发送,因为数据量小,传输速度快
- 自包含(Self-contained) 负载中包含了所有用户所需要的信息,避免了多次查询数据库
JWT的创建与使用
引入jwt依赖
<!-- https://mvnrepository.com/artifact/com.auth0/java-jwt -->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.10.3</version>
</dependency>
创建
void createJWT() {
Calendar instance = Calendar.getInstance();
instance.add(Calendar.SECOND,100);
String sign = JWT.create()
.withClaim("userId", 21)//Payload
.withClaim("username", "longda")
.withExpiresAt(instance.getTime()) //指定令牌过期时间
.sign(Algorithm.HMAC256("!@HKGfhjk"));//Signature
System.out.println(sign);
}
使用
void TestSign(){
//创建验证对象
JWTVerifier verifier = JWT.require(Algorithm.HMAC256("!@HKGfhjk")).build();
DecodedJWT verify = verifier.verify("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1OTc1NzE0NTksInVzZXJJZCI6MjEsInVzZXJuYW1lIjoibG9uZ2RhIn0.8zljCZy6Vg64spyMdY6JHDudImNmmFb8i33vMZ39dv4");
//对应生成的令牌
System.out.println(verify.getClaim("userId").asInt());
System.out.println(verify.getClaim("username").asString());
}
封装JWT工具类
public class JWTUtil {
private static final String Signature = "!@HKGfhjk";
/**
* 生成token
* @param map
* @return
*/
public static String getToken(Map<String ,String> map){
Calendar instance = Calendar.getInstance();
instance.add(Calendar.DATE,7); //默认七天过期
//创建jwt builder
JWTCreator.Builder builder = JWT.create();
//payload
map.forEach((k,v)->{
builder.withClaim(k,v);
});
//指定builder过期时间
String token = builder.withExpiresAt(instance.getTime())
.sign(Algorithm.HMAC256(Signature));//签名
return token;
}
/**
* 验证token 合法性
*/
public static DecodedJWT vertify(String token){
return JWT.require(Algorithm.HMAC256(Signature)).build().verify(token);
}
// /**
// * 获取token信息方法
// */
// public static DecodedJWT getTokenInfo(String token){
// DecodedJWT verify = JWT.require(Algorithm.HMAC256(Signature)).build().verify(token);
// return verify;
// }
}
业务中使用JWT
新建JWT拦截器
public class JWTInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
Map<String ,Object> map = new HashMap<>();
//获取请求头中的令牌
String token = request.getHeader("token");
try {
DecodedJWT vertify = JWTUtil.vertify(token);
return true; //放行请求
} catch (SignatureVerificationException e) {
e.printStackTrace();
map.put("msg","无效签名!");
}catch (TokenExpiredException e){
e.printStackTrace();
map.put("msg","token过期!");
}catch (AlgorithmMismatchException e){
e.printStackTrace();
map.put("msg","token算法不一致!");
}catch (Exception e){
e.printStackTrace();
map.put("msg","token无效!");
}
map.put("state",false);//设置状态
String json = new ObjectMapper().writeValueAsString(map);
response.setContentType("application/json;charset=UTF-8");
response.getWriter().println(json);
return false;
}
}
配置拦截器
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new JWTInterceptor())
.addPathPatterns("/**") //其他接口token验证
.excludePathPatterns("/user/**"); //用户验证放行
}
}
完成业务代码
@PostMapping("/user/test")
public Map<String ,Object> test(HttpServletRequest request){
Map<String, Object> map = new HashMap<>();
//处理业务逻辑
String token = request.getHeader("token");
DecodedJWT vertify = JWTUtil.vertify(token);
log.info(vertify.getClaim("id").asString());
log.info(vertify.getClaim("name").asString());
map.put("state",true);
map.put("msg","required success");
return map;
}
使用拦截器处理JWT的token验证可以减少代码的冗余

浙公网安备 33010602011771号