JWT详解与基本使用(保姆教程)

前言: 最近准备写一篇关于security前后端分离场景下的认证与授权文章,里面使用到了jwt,所以就写了一篇jwt的文章,作为开头小菜😋

概述

讲jwt之前,先讲一下什么是token?

token其实就是服务端在用户认证成功(登陆成功)之后生成的一串加密字符串,用户每次发送请求 请求后端资源时也发送给服务端,从而验证用户身份的合法地位(即你是谁,有没有资格访问),允许用户访问该令牌允许的路由、服务和资源等,所以说token的主要作用就是用户授权,如下图

image.png

什么是jwt?

jwt就是JSON Web Token,他是一种使用密钥(使用 HMAC 算法)或使用 RSA 或 ECDSA 的公钥/私钥对进行加密的token,也是目前最常用的一种token

构成

jwt由三部分组成,分别是header(头部)、payload(有效载荷)、signature(签名)组成,用 . 进行连接,所以token(代指JWT)通常的格式是 : aaa.bbb.ccc

头部通常由两部分组成:令牌的类型(即 JWT)和正在使用的签名算法(如 HMAC SHA256 或 RSA),例如:

{ 
   "typ": "JWT" ,
   "alg": "HS256"
}

然后此 JSON 被 Base64Url 编码形成 JWT 的第一部分

另外,常用的签名算法还有:

HS256 HS384 HS512 PS256 PS384 PS512 RS256 RS384 RS512 ES256 ES256K 等,大家根据自己习惯选择签名算法(这个影响不大)

算法原理啥的就不说了,大家有兴趣自己去百度😊

Payload

payload谷歌翻译为有效载荷,但我觉得其实就是内容的意思,我们可以把想要存的一些信息以json字符串的形式存储在这里。比如用户id等用户信息。同时还可以存放iss(颁发者),exp(到期时间)等声明(详情可以查看官方文档)。例如:

{
   "id":1,
   "username" : "mango",
   "exp":"1664812343"
}

然后此json也会被 Base64Url 编码形成 JWT 的第二部分

Signature

签名用于验证token在此过程中未被更改,并且对于使用私钥签名的令牌,它还可以验证 JWT 的发送者是否是它所说的人。

通过编码后的header、编码后的payload然后使用header中声明的加密算法进行加盐secret组合加密得到一个字符串,这就是token的第三部分

例如,如果要使用 HMAC SHA256 算法,将按以下方式创建签名:

HMACSHA256( 
base64UrlEncode(header) + "." + base64UrlEncode(payload), 
secret)

注意: secret是保存在服务端并进行签发的,secret就是用来进行jwt的签发与验证,就是相当于一个密钥,一旦泄露给客户端,意味着客户端也能自我签发jwt

总结

所以jwt除了用于token鉴权以外,还可以进行信息的安全传输,因为通过签名可以确定用户(使用私钥)和防止内容被篡改。(当然缺点就是传输的信息是公开的)

注意:因为token用来加密的算法仅仅是用于加密签名,防止token被篡改,而存储用户信息的payload仅仅是用Base64Url编码而成,其他人可以通过解码获取信息,所以不建议把用户敏感信息(如用户密码)存入token(防止泄漏)😱

token的基本使用

项目依赖,这里使用的是auth0,可以去官网根据自己算法需要选择依赖

<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>3.18.2</version>
</dependency>

生成token😊

public class Main {
    public static void main(String[] args) {
        //时间工具类
        Calendar instance = Calendar.getInstance();
        //设置过期时间  单位:SECOND秒  一个小时失效
        instance.add(Calendar.SECOND,60*60);
        
        JWTCreator.Builder builder = JWT.create()
                //添加键值对数据
                .withClaim("id", 1)
                //添加过期时间 exp 也可以添加key为exp valus为到期时间的时间戳和这个效果一样
                //.withClaim("exp",1664815770)
                .withExpiresAt(instance.getTime());
        // 选择签名算法HMAC256 添加密钥字符串mango(盐)
        String token = builder.sign(Algorithm.HMAC256("mango"));
        //输出token
        System.out.println(token);

    }
}

验证token并获取数据😱

public class Main {
    public static void main(String[] args) {
        //验证的token
        String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6MSwiZXhwIjoxNjY0ODIwMDUzfQ.SNy4Venx_AE8eqow6c3bVNwbmlX7-iz8OiDiPntY6DA";
        try{
            //提供密钥字符串(盐)和token
            DecodedJWT jwt = JWT.require(Algorithm.HMAC256("mango")).build().verify(token);
            //输出存储在Payload中键值对key为id的value 即id
            System.out.println(jwt.getClaim("id"));
            //token设置过期时间就会有key为exp的键值对 value是到期时间的时间戳
            System.out.println(jwt.getClaim("exp"));
        }catch (TokenExpiredException e){
             //令牌过期抛出异常
            System.out.println("令牌过期");
        }catch (Exception e){
            //token非法验证失败抛出异常
            System.out.println("检验失败");
        }
    }
}

这就是token最基本的生成与验证使用,实际使用中一般是集成一个工具类使用。

结语:因为打算写一篇关于security前后端分离场景下的认证与授权文章,其中就是使用security+jwt实现的认证授权,所以就先写一篇有关于jwt的文章,大家要是觉得有用的话点个赞吧😘,下篇见😊

posted @ 2022-10-04 02:42  芒果mango404  阅读(346)  评论(0编辑  收藏  举报