欢迎各位大神给小弟指点指点,嘻嘻
内容说的不对还望指出来,一定及时改正!
1. JWT的使用
为什么使用JWT,而不使用session?
根据我的了解(大白话),传统session是保存在服务器中,而JWT是保存在浏览器本地的,使用JWT的好处就是不占用服务器的内存,使用session的话用户每次访问都会携带sessionId去服务器中找它对应的session,找的到就验证成功,找不到就失败,证明没有登录,跳转到登录页面。
使用JWT的话,由于它是保存在浏览器本地的,不会占用服务器的内存,这是一点好处(目前只了解到这些),在前后端分离的系统中对比session,Jwt会更好一点,具体好在哪,其实小编也不清楚,这里只是记录一下jwt的使用,嘻嘻
header 和 payload 都是用base64来解析和加密的,他们的本体是json数据,咱们看到的只是用base64加密后的
# jwt的结构:
> string ===> header.payload.singnature
### 1.令牌组成
- 1.标头(Header)
- 2.有效载荷(Payload)
- 3.签名 (Signature)
- 因此,JWT通常如下所示 : xxxxxx.yyyyyyy.zzzzzz
- 引入依赖
<!--引入jwt-->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.4.0</version>
</dependency>
- 生成Token
public final static long EXPIRE_TIME=30*60*1000;//放在类中 ,30分钟的毫秒数
//获取时间,用来做token的过期时间,设置30分钟
Date date=new Date(System.currentTimeMillis()+EXPIRE_TIME)
Map<String,Object> map=new HashMap<>();
String sign = JWT.create().withHeader(map) //header 这个不设置也可以
.withClaim("userId", 12)//payload 存储非敏感的信息 例如用户账号,不能存密码,防止被人解析
.withExpiresAt(date)//指定令牌的过期时间
.sign(Algorithm.HMAC256("!we2123")) ;//签名 保密复杂
System.out.println(sign); //输出结果
# 生成结果
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2MjY1MzQ3OTIsInVzZXJJZCI6MTIsInVzZXJuYW1lIjoiamZwIn0.GhUCPBptbASHng-8DkEFIw9jYB2IWStUj3SEgm53x84
2. 验证token
验证时可以加一个
try {
} catch(){
例如验证出现了异常,就证明验证失败 直接return false;
}
//创建验证对象
//验证时一定要跟生成时的 算法 和 签名 一致
JWTVerifier build = JWT.require(Algorithm.HMAC256("!we2123")).build();
DecodedJWT verify = build.verify(" 这里放token ");
/**
以上两行代码就已经完成验证了,如果没有出异常,就验证成功!
出现了就是验证失败 ,前提要保证算法一定要一致,不要出现算法不一致异常
*/
//获取payload存储的信息
System.out.println(verify.getClaim("userId").asInt()); //存什么类型 就as什么类型,否则为null
System.out.println(verify.getClaim("username").asString());
Date expiresAt = verify.getExpiresAt(); // 查看token过期时间
SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String format = simpleDateFormat.format(expiresAt);
System.out.println(format);
3. jwt验证出现的异常
验证时会先验证签名,再验证令牌有没有过期
# 签名验证异常 (生成时和验证时的签名不一致,会出现此异常)
- SignatureVerificationException
# 算法不匹配异常 (生成时和验证时的算法不一致,会出现此异常)
- AlgorithmMismatchException
# 令牌过期异常 (生成时设置的时间超时后,再次验证会出现此异常)
- TokenExpiredException
# 失效的payload异常 (出现此异常的原因有:可能有人使用base64解析payload,更改了数据payload里解析的数据,再次传过来,验证时会出现此异常)
- InvalidClaimException
4. 封装工具类
/**
* @Description
* @Author 金飞鹏 2021/7/18 9:56
*/
public class JWTUtil {
//30分钟
public final static long EXPIRE_TIME=30*60*1000;
/**
* 生成token header.payload.sing
*/
public static String getToken(Map<String, String> map){
Date date=new Date(System.currentTimeMillis()+EXPIRE_TIME); //默认30分钟过期
//创建JWT builder
JWTCreator.Builder builder = JWT.create();
// payload
map.forEach((k,v)->{
builder.withClaim(k,v); //这里可以存放 用户id,用户名
});
//指定过期时间,sign ,生成token 这里的签名是指定好的
//实际项目中可以 接收用户的密码来做签名,这样每一个用户对应一个签名
java.lang.String token = builder.withExpiresAt(date).sign(Algorithm.HMAC256("1234"));
return token;
}
/**
* 验证token合法性
*/
public static boolean verify(String token){
try {
//如果抛出异常,证明签名不一致 / token过期
JWT.require(Algorithm.HMAC256("1234")).build().verify(token);
return true;
}catch (Exception e){
return false;
}
}
/**
* 获得token中的信息无需secret解密也能获得
*/
public static String getUserName(String token){
DecodedJWT decode = JWT.decode(token);
//假设存储的是一个phone
String phone = decode.getClaim("phone").asString();
return phone;
}