JTW令牌技术 -- 登录校验

一. JWT令牌介绍

JWT全称 JSON Web Token (官网:https://jwt.io/),定义了一种简洁的、自包含的格式,用于在通信双方以json数据格式安全的传输信息。由于数字签名的存在,这些信息是可靠的。

  • 简洁:是指jwt就是一个简单的字符串。可以在请求参数或者是请求头当中直接传递。
  • 自包含:指的是jwt令牌,看似是一个随机的字符串,但是我们是可以根据自身的需求在jwt令牌中存储自定义的数据内容。如:可以直接在jwt令牌中存储用户的相关信息。
  • 简单来讲,jwt就是将原始的json数据格式进行了安全的封装,这样就可以直接基于jwt在通信双方安全的进行信息传输了。

JWT的组成: (JWT令牌由三个部分组成,三个部分之间使用英文的点来分割)

  • 第一部分:Header(头), 报头通常由两部分组成:令牌的类型(JWT)和使用的签名算法(如HMAC SHA256或RSA)。例如:{"alg":"HS256","type":"JWT"}
  • 第二部分:Payload(有效载荷),携带一些自定义信息、默认信息等。 例如:{"id":"1","username":"Tom"}
  • 第三部分:Signature(签名),防止Token被篡改、确保安全性。将header、payload,并加入指定秘钥,通过指定签名算法计算而来。

下面显示了一个JWT,它对前一个报头和有效负载进行了编码,并使用密钥对其进行了签名。

签名的目的就是为了防jwt令牌被篡改,而正是因为jwt令牌最后一个部分数字签名的存在,所以整个jwt 令牌是非常安全可靠的。一旦jwt令牌当中任何一个部分、任何一个字符被篡改了,整个令牌在校验的时候都会失败,所以它是非常安全可靠的。

JWT是如何将原始的JSON格式数据,转变为字符串的呢?

  • 其实在生成JWT令牌时,会对JSON格式的数据进行一次编码:进行base64编码
  • Base64:是一种基于64个可打印的字符来表示二进制数据的编码方式。既然能编码,那也就意味着也能解码。所使用的64个字符分别是A到Z、a到z、 0- 9,一个加号,一个斜杠,加起来就是64个字符。任何数据经过base64编码之后,最终就会通过这64个字符来表示。当然还有一个符号,那就是等号。等号它是一个补位的符号
  • 需要注意的是Base64是编码方式,而不是加密方式。

二. 生成与校验

要想使用JWT令牌,需要先引入JWT的依赖:

java 复制代码
<!-- JWT依赖-->
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>

2.1 生成令牌

在base64编码解码网上随便生成一个base64密钥

编写一个测试类:(密钥也可以直接传递一个字符串)

java 复制代码
// 生成jwt令牌
@Test
public void testGenerateJwt() {
    Map<String, Object> dataMap = new HashMap<>();
    dataMap.put("id", 1);
    dataMap.put("username", "admin");
    String jwt = Jwts.builder().signWith(SignatureAlgorithm.HS256, "b2po55yf5biF") // 指定加密算法及密钥
            .addClaims(dataMap) // 添加自定义信息
            .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60)) // 设置过期时间(毫秒)
            .compact();// 生成令牌
    System.out.println(jwt);
}

再去官网进行调试

2.2 校验令牌

编写测试类

java 复制代码
// 解析令牌
@Test
public void testParseJWT() {
    String token = "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MSwidXNlcm5hbWUiOiJhZG1pbiIsImV4cCI6MTc2NTA4NzY4NX0.vxiKt7Ld-9wxPj2jfvPFZ_tCyvpWU7HPbkhURp_0ThQ";
    Claims claims = Jwts.parser().setSigningKey("b2po55yf5biF")
            .parseClaimsJws(token)
            .getBody();
    System.out.println(claims);
}

JWT解码和编码的区别:

  • 编码JWT涉及到将报头和有效负载转换为紧凑的url安全格式。标头(说明签名算法和令牌类型)和有效负载(包括主题、过期和发布时间等声明)都被转换为JSON,然后对Base64URL进行编码。然后将这些编码的部分与一个点连接起来,然后使用头中指定的带有密钥或私钥的算法生成签名。此签名也是Base64URL编码的,从而产生最终的JWT字符串,该字符串以适合传输或存储的格式表示令牌。
  • 解码JWT通过将Base64URL编码的报头和有效负载转换回JSON来逆转这个过程,允许任何人在不需要密钥的情况下读取这些部分。然而,在这种情况下,"解码"通常扩展到包括对令牌签名的验证。此验证步骤包括使用最初使用的相同算法和密钥重新签名已解码的报头和有效负载,然后将此新签名与JWT中包含的签名进行比较。如果它们匹配,则确认令牌的完整性和真实性,确保自发行以来未被篡改。

三. 实战应用

将生成和解析jwt封装成一个工具类:

LoginInfo实体类:

编写Service层代码:

java 复制代码
// 登录
@Override
public LoginInfo login(Emp emp) {
    Emp e = empMapper.selectByUsernameAndPassword(emp);
    // 存在
    if(e != null){
        LoginInfo info = new LoginInfo();
        info.setId(e.getId());
        info.setUsername(e.getUsername());
        info.setName(e.getName());
        // 生成令牌
        Map<String, Object> claims = new HashMap<>();
        claims.put("id", e.getId());
        claims.put("username", e.getUsername());
        String jwt = JwtUtils.generateJwt(claims);
        info.setToken(jwt);
        return info;
    }
    // 不存在
    return null;
}

测试

那怎么样来统一拦截到所有的请求校验令牌的有效性呢?这里我们会用到两种解决方案:Filter过滤器Interceptor拦截器

相关推荐
悟能不能悟1 天前
JAVA 对象转为二级制流,再转化为base64
java·开发语言
潲爺1 天前
Java-IO笔记
java·笔记·学习
JH30731 天前
静态资源映射相关问题解答
java
爬山算法1 天前
Hibernate(6) Hibernate支持哪些数据库?
java·数据库·hibernate
爱吃牛肉的大老虎1 天前
Spring WebFlux与SpringMVC 对比讲解
java·后端·spring
QQ 31316378901 天前
文华财经软件指标公式期货买卖信号提示软件
java·前端·javascript
老华带你飞1 天前
房屋租赁管理系统|基于java+ vue房屋租赁管理系统(源码+数据库+文档)
java·开发语言·前端·数据库·vue.js·spring boot·后端
jqrbcts1 天前
关于发那科机器人如何时时把角度发给PLC
java·服务器·网络·人工智能
TheITSea1 天前
Java中的Optional:从入门到精通
java·开发语言
程序员侠客行1 天前
Mybatis入门到精通 一
java·架构·mybatis