JWT的使用+初体验

欢迎各位大神给小弟指点指点,嘻嘻
内容说的不对还望指出来,一定及时改正!

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
  1. 引入依赖
 <!--引入jwt-->
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.4.0</version>
        </dependency>
  1. 生成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;
    }
上一篇:挖洞经验 | 构造基于时间的盲注漏洞(Time-Based SQLi)


下一篇:后台获取request payload传过来的数据