通过 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);
    }

运⾏结果:

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

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

相关推荐
鱼宵17 小时前
LangChain4j 结构化输出:让模型吐出 Java 对象,JSON 不再手写解析
java·开发语言·json·langchain4j
leisoo809720 小时前
融资融券数据怎么查两融指标含义与杠杆观察方法 IG50免费开源股票数据API接口
开发语言·jvm·数据库·python·json
胖头鱼的鱼缸(尹海文)2 天前
胖头鱼的技术专栏-474 从能跑到能上线:PG SplitJSON 0.2.0 和 0.1.0 差在哪(20261008)
postgresql·json
?? Daisy3 天前
Claude Code 接入 GPT:settings.json 两种配置方法(2026-10)
gpt·json
小静AI工程实验室3 天前
Python 爬虫解析 JSON-LD:多块 script、@graph 与坏数据的 9 个边界
爬虫·python·json
goehou4 天前
LLM 结构化输出全解:从 Prompt 约束到 Schema 硬保证,三层实现怎么选
ai·llm·json·agent·教程·结构化输出
独立开发者阿乐4 天前
结构化数据 JSON-LD 实战:让 AI 读懂你的网页
人工智能·json·结构化数据·geo优化·json-ld·ai收录·faqpage
liangshanbo12156 天前
高级前端面试题:package.json 常见字段
前端·json
梦帮科技6 天前
【3.0修订版】创世与节点工程:genesis.json 与 node.toml 解剖
数据结构·算法·json·去中心化·区块链·智能合约·信任链
weixin_440730507 天前
内置函数、json文本、pickle二进制
开发语言·python·json