通过 JWT(JSON Web Token)实现令牌

关于令牌的概念推荐看令牌技术实现登录的思路

前言

令牌本质就是⼀个字符串,它的实现⽅式有很多,我们采⽤⼀个 JWT 令牌来实现.

介绍

JWT全称:JSON Web Token

官⽹: https://jwt.io/

JSON Web Token(JWT)是⼀个开放的⾏业标准(RFC 7519),⽤于客户端和服务器之间传递安全可靠的信息.

其本质是⼀个 token(令牌),是⼀种紧凑的 URL 安全⽅法.

JWT 组成

JWT由三部分组成,每部分中间使⽤点 (.) 分隔,⽐如:aaaaa.bbbbb.cccc

• **Header(头部)**头部包括令牌的类型(即JWT)及使⽤的哈希算法(如 HMAC SHA256 或RSA )

Payload(负载) 负载部分是存放有效信息的地⽅,⾥⾯是⼀些⾃定义内容.⽐如: {"userId":"123","userName":"zhangsan"} ,也可以存 jwt 提供的现场字段,⽐如 exp(过期时间戳)等.此部分不建议存放敏感信息,因为此部分可以解码还原原始内容.

Signature(签名) 此部分⽤于防⽌ jwt 内容被篡改,确保安全性

防⽌被篡改,⽽不是防⽌被解析. JWT 之所以安全,就是因为最后的签名. jwt 当中任何⼀个字符被篡改,整个令牌都会校验失败.就好⽐我们的⾝份证,之所以能标识⼀个⼈的⾝份,是因为他不能被篡改,⽽不是因为内容加密.(任何⼈都可以看到⾝份证的信息, jwt 也是)

如下图:

当我们将正确的令牌进行解码时,就能得到令牌中的信息

对左边部分的信息, 使⽤Base64Url 进⾏编码,合并在⼀起就是 jwt 令牌Base64 是编码⽅式,⽽不是加密⽅式

JWT令牌生成和校验

1. 引⼊ JWT 令牌的依赖

java 复制代码
<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-api -->
<dependency>
 <groupId>io.jsonwebtoken</groupId>
 <artifactId>jjwt-api</artifactId>
 <version>0.11.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-impl -->
<dependency>
 <groupId>io.jsonwebtoken</groupId>
 <artifactId>jjwt-impl</artifactId>
 <version>0.11.5</version>
 <scope>runtime</scope>
</dependency>
<dependency>
 <groupId>io.jsonwebtoken</groupId>
 <artifactId>jjwt-jackson</artifactId> <!-- or jjwt-gson if Gson is 
preferred -->
 <version>0.11.5</version>
 <scope>runtime</scope>
</dependency>

2. 使⽤ Jar 包中提供的 API 来完成 JWT 令牌的⽣成和校验

⽣成令牌:

java 复制代码
@SpringBootTest
public class JwtUtilTest {
    //使用 Jwt 令牌最关键的是生成令牌和校验令牌

    //令牌的过期时间 单位(毫秒)1小时
    private static final long expiration=60*60*1000;
    //密钥
    private static final String secretString="sfo9tYSzXYjGIzAbhFBs6wHhxiWZZsA5QFCHV2yLsg0=";
    /**
     * 安全密钥
     * Keys 调用 hmacShaKeyFor() 方法来创建,参数是根据 BASE64 解码后的密钥
     * */
    private static final SecretKey SECRET_KEY=Keys.hmacShaKeyFor(Decoders.BASE64.decode(secretString));

    /**
     * 1.生成令牌
     * */
    @Test
    public void genJwt(){
        Map<String,Object> claim=new HashMap<>();
        claim.put("id",1);
        claim.put("userName","张三");
        String jwt= Jwts.builder()
                .setClaims(claim)   //设置自定义内容(负载)
                .setIssuedAt(new Date())    //设置签发时间
                .setExpiration(new Date(System.currentTimeMillis()+expiration))     //设置过期时间
                .signWith(SECRET_KEY)   //设置签名算法
                .compact();

        System.out.println(jwt);
    }
}

输出创建的令牌为:eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MSwidXNlck5hbWUiOiLlvKDkuIkiLCJpYXQiOjE3MDY3NjkyMTYsImV4cCI6MTcwNjc3MjgxNn0.7vkw8ee6qcYaQzBwAbWb-Yon8bOt8PH8Xad83gJv2LY

创建令牌的大致流程;

1.先自己写或者生成一个密钥(密钥的长度必须大于256个字节)

2.调用多个方法根据密钥生成一个安全密钥(详情看 SECRET_KEY 的创建过程)

3.调用接口设置令牌的相关属性,安全密钥需要用来设置签名算法(详情看 jwt 的创建)

生成密钥

对密钥有⻓度和内容的要求,建议使⽤io.jsonwebtoken.security.Keys#secretKeyFor(signaturealgalgorithm)⽅法来创建⼀个密钥

详细创建过程如下:

java 复制代码
/**
     * 生成密钥
     * 对于密钥有⻓度和内容的要求,建议使⽤
     * io.jsonwebtoken.security.Keys#secretKeyFor(signatureAlgorithm)⽅法来创建⼀个密钥
     * */
    @Test
    public void genSecret(){
        //创建了一个密钥生成器
        //参数是一个枚举类型,表示加密算法
        Key key=Keys.secretKeyFor(SignatureAlgorithm.HS256);
        String secretString=Encoders.BASE64.encode(key.getEncoded());
        System.out.println(secretString);
    }

校验令牌

完成了令牌的⽣成,我们需要根据令牌,来校验令牌的合法性(以防客户端伪造)

我们把⽣成的令牌通过官⽹进⾏解析,就可以看到我们存储的信息了

  1. HEADER 部分可以看到,使⽤的算法为 HS256

  2. PAYLOAD 部分是我们⾃定义的内容, iat 表示创建时间,exp 表⽰过期时间

  3. VERIFY SIGNATURE 部分是签名,通过签名算法计算出来,所以不会解析

我们当然也可以通过代码来校验令牌的合法性,代码如下:

java 复制代码
 /**
     * 解析令牌
     * 需要根据令牌,来校验令牌的合法性(以防客户端伪造)
     * */
    @Test
    public void parseJwt(){
        String token="eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MSwidXNlck5hbWUiOiLlvKDkuIkiLCJpYXQiOjE3MDY3NjkyMTYsImV4cCI6MTcwNjc3MjgxNn0.7vkw8ee6qcYaQzBwAbWb-Yon8bOt8PH8Xad83gJv2LY";
        //创建解析器,设置签名所用的安全密钥
        JwtParserBuilder jwtParserBuilder=Jwts.parserBuilder().setSigningKey(SECRET_KEY);

        //解析 token
        Claims claims = jwtParserBuilder.build().parseClaimsJws(token).getBody();
        System.out.println(claims);
    }

运⾏结果:

令牌解析后,我们可以看到⾥⾯存储的信息,如果在解析的过程当中没有报错,就说明解析成功了.

令牌解析时,也会进⾏时间有效性的校验,如果令牌过期了,解析也会失败.修改令牌中的任何⼀个字符,都会校验失败,所以令牌⽆法篡改

相关推荐
一杯科技拿铁6 小时前
从 XML 到 JSON,再到 CBOR:数据交换格式的演进之路
xml·json
爱编码的程序员2 天前
python 处理json、excel、然后将内容转化为DSL语句,适用于数据处理(实用版)
人工智能·python·ai·json·excel·数据处理·dsl
wtsolutions2 天前
免费MCP: JSON 转 Excel MCP
json·excel·api·csv·mcp·wtsolutions
杨DaB2 天前
【项目实践】在系统接入天气api,根据当前天气提醒,做好plan
java·后端·spring·ajax·json·mvc
hqxstudying3 天前
前后端交流
java·css·后端·html·json
Vic101014 天前
Hutool 的完整 JSON 工具类示例
开发语言·json
电商数据girl4 天前
如何利用API接口与网页爬虫协同进行电商平台商品数据采集?
大数据·开发语言·人工智能·python·django·json
拷斤锟5 天前
使用Excel解析从OData API获取到的JSON数据
数据库·json·excel
有育哥无奔波6 天前
是采用示例模板,还是采用json的结构化数据,哪种方式会让llm的输出更加稳定?
json
小小李程序员6 天前
JSON.parse解析大整数踩坑
开发语言·javascript·json