一、jwt的组成部分
1、Header(头部)
常见的属性有:alg(签名加密使用的算法),typ(标识token,默认为JWT),是json字符串类型。
2、Payload(有效荷载)
用来承载传递的数据,是josn字符串类型。它的属性值对是Claim类,调用Payload的属性值对时,采用DecodedJWT类的getClaim方法,可以用asString方法转换成String类型。
3、Signture(签名)
就是使用base64编码后的header和payload数据,通过header中alg属性指定的算法进行加密生成哈希。
二、JWT运行机制
1、发送第一次请求,携带用户信息的username和password。当有拦截器拦截路径时,第一次访问只能访问未被拦截的地址。
//拦截器
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new JWTInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/login1");
super.addInterceptors(registry);
}
}
2、当用户信息的username和password登录成功时,通过JWT工具生成token。在jwt工具中可以设置header和payload的属性,withClaim方法用来放入数据,sgin方法中放入使用算法(一般使用HMAC256算法,该算法需要设置盐值(密钥))签名加密。
//设置盐值(密钥)
private static String salt="oiaho2h434";
//生成token
public static String createToken(LoginUser user){
LoginUser user1 = getLoginUser();
//创建一个JWT
JWTCreator.Builder builder = JWT.create();
//设置JWT的头部 alg typ
Map map1 = new HashMap();
map1.put("alg","HMAC256");
map1.put("typ","JWT");
builder.withHeader(map1);
//设置 JWT的有效荷载 Payload
Map map2 = new HashMap();
map2.put("username",user1.getUsername());
map2.put("password",user1.getPassword());
builder.withPayload(map2);
//给JWT加密
builder.withClaim("salt",salt).withClaim("user",user.getUsername());
String token = builder.sign(Algorithm.HMAC256(salt));
return token;
}
3、后端每次收到请求的时候,验证是否存在JWT 。如果存在,通过携带JWT 访问被拦截的路径,这时不会被拦截器拦截。JWT串会在JWT工具中被解析成用户信息,进行最终校验。主要是判断JWT中的token,需要注意token是否为null,token的报错信息。最后是解析过后的用户信息的判断用户是否存在,用户账号和密码是否一致。
public static Map verifyToken(String token){
//判断token是否为空
if(token == null){
System.out.println("token不能为空");
}
//把JWT进行解密 得到 DecodedJWT 这个就是JWT
//JWT.build构建内部类
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(salt)).build();
//解密的过程如果token出错了,有错误信息
Map map = new HashMap();
try {
// DecodedJWT decodedJWT = JWTUtils.verifyToken(token);
DecodedJWT verify = verifier.verify(token);
//从JWT对象中获取我需要的部分 有效荷载
// 有效荷载 用户名+用户密码
String username = verify.getClaim("username").asString();
String password = verify.getClaim("password").asString();
//如果出现错误:错误信息:用户相关的错误信息
LoginUser user1 = getLoginUser();
//判断用户是否存在
if(username.equals(user1.getUsername())){
//区判断用户的账号密码是否一致
if (username.equals(user1.getUsername()) && password.equals(user1.getPassword())){
map.put("success","true" );
map.put("msg","登录成功");
}else{
map.put("msg","密码错误");
}
}else{
map.put("msg","用户不存在");
}
return map;
}catch (SignatureVerificationException e){
map.put("msg","无效签名1");
}catch (TokenExpiredException e){
map.put("msg","token过期!");
}catch (AlgorithmMismatchException e){
map.put("msg","token加密算法不一致");
}catch (Exception e){
map.put("msg","无效签名2");
}
return map;
}