我们一起聊一聊JWT的那些事

我们一起聊一聊JWT的那些事

在这里插入图片描述
一切美好,如期而至…

什么是JWT

JWT,全称为 JSON Web Token,是一种用于在网络上安全地传递信息的开放标准(RFC 7519)。JWT 是一种紧凑且独立的方式,用于在各方之间以 JSON 对象形式安全地传输信息。该信息可以被验证和信任,因为它是经过数字签名的。JWT 可以使用秘密(使用 HMAC 算法)或使用公钥/私钥对(使用 RSA 或 ECDSA 算法)进行签名。

JWT 通常用于身份验证和信息交换。在身份验证方面,当用户成功登录后,服务器会生成一个包含用户标识信息的 JWT,并将其发送回客户端。客户端随后可以在每个后续请求中包含 JWT,以证明其身份。在信息交换方面,由于 JWT 的信息是经过签名的,接收方可以验证其来源和完整性。

JWT 的结构如下:

xxxxx.yyyyy.zzzzz

其中,每一部分由点号分隔:

  • 第一部分是头部(Header),通常包含两部分信息:令牌类型(JWT)和所使用的签名算法,例如 HMAC SHA256 或 RSA。

  • 第二部分是载荷(Payload),包含声明(claims)。声明是关于实体(通常是用户)和其他数据的声明。有三种类型的声明:注册的声明,公共的声明和私有的声明。

  • 第三部分是签名(Signature),用于验证消息在传递过程中没有被篡改,并确保消息的发送方是可信的。

JWT 的优点包括:

  1. 自包含: JWT 包含了所有需要的信息,减少了在服务器存储会话状态的需要。

  2. 跨域: 由于 JWT 是在各方之间传递的标准格式,可以在不同域之间轻松传递信息。

  3. 安全性: 当使用数字签名时,可以确保 JWT 的来源和完整性。

然而,需要注意的是,为了确保安全性,不应该在 JWT 中存储敏感信息,尤其是在使用对称加密算法的情况下。对于敏感信息,最好在服务器端进行验证。

和普通的token有啥区别子

JSON Web Token(JWT)和普通的 token 之间有一些关键区别,主要涉及到它们的结构、用途和安全性等方面:

  1. 结构差异:

    • 普通 Token: 通常是一个简单的字符串,可能是随机生成的一串字符,例如 UUID(Universally Unique Identifier)。
    • JWT: 具有明确定义的结构,包含头部、载荷和签名三个部分,并以点号分隔。这种结构使得 JWT 可以携带更多的信息,并且具有更灵活的用途。
  2. 内容携带:

    • 普通 Token: 只是一个标识符,不携带其他有关用户或实体的信息。
    • JWT: 可以携带一些声明(claims),这些声明包含有关用户、角色、权限等信息。由于 JWT 是基于 JSON 格式的,因此它可以以一种结构化的方式携带更多的信息。
  3. 签名和验证:

    • 普通 Token: 通常需要在服务器端进行验证,但不一定使用数字签名或加密。
    • JWT: 通常使用数字签名来验证其真实性。这使得 JWT 在传递过程中能够被验证,确保它没有被篡改。JWT 还支持使用非对称加密来提供额外的安全性。
  4. 安全性:

    • 普通 Token: 可能存在被伪造或截获的风险,因为它没有内置的安全机制。
    • JWT: 通过数字签名或加密,提供了一定程度的安全性。如果使用对称加密,需要确保密钥的安全性;如果使用非对称加密,可以更安全地传递公钥。
  5. 用途:

    • 普通 Token: 通常用于简单的身份验证,例如在会话中保存用户的登录状态。
    • JWT: 由于其结构和灵活性,可用于更广泛的用途,包括身份验证、信息交换和声明传递。

总体而言,JWT 是一种更为灵活、结构化且安全的令牌,适用于需要携带更多信息和在跨域环境中进行安全传递的场景。普通 Token 更适合简单的身份验证场景。选择使用哪种令牌取决于具体的应用需求和安全要求。

如何生成JWT

前端生成

生成 JSON Web Tokens(JWT)涉及以下步骤:

  1. 选择一个密钥: JWT 使用密钥进行签名以确保数据的完整性和来源。密钥可以是对称密钥(HMAC算法)或非对称密钥(RSA或ECDSA算法)。

  2. 构建JWT的头部(Header): JWT的头部包含有关令牌的元信息,如算法和令牌类型。这部分信息通常以Base64编码的JSON字符串表示,并放置在JWT的第一部分。

  3. 构建JWT的载荷(Payload): 载荷包含有关JWT主体(subject)的声明和其他信息。与头部一样,这部分信息也是以Base64编码的JSON字符串表示,并放置在JWT的第二部分。

  4. 对头部和载荷进行签名: 使用选择的算法和密钥对头部和载荷进行签名。签名是通过将Base64编码的头部和载荷字符串与密钥一起进行加密而生成的。

  5. 将头部、载荷和签名组合成JWT: 将Base64编码的头部、Base64编码的载荷和签名以点号分隔组合在一起形成JWT。

下面是一个简单的例子,使用Node.js中的jsonwebtoken库生成JWT:

const jwt = require('jsonwebtoken');

// 构建头部
const header = {
    
    
  "alg": "HS256",  // HMAC SHA-256算法
  "typ": "JWT"
};

// 构建载荷
const payload = {
    
    
  "sub": "1234567890",  // 主体标识
  "name": "John Doe",
  "iat": Math.floor(Date.now() / 1000)  // 签发时间(当前时间)
};

// 选择密钥
const secretKey = "yourSecretKey";

// 生成JWT
const token = jwt.sign(payload, secretKey, {
    
     header });

console.log(token);

在实际应用中,建议使用更安全的随机生成的密钥,并根据具体的需求选择适当的算法和配置选项。生成JWT的代码示例可能会根据所选的编程语言和库而有所不同,但上述步骤是通用的。

后端生成

在Java中,你可以使用 io.jsonwebtoken 库来生成 JSON Web Tokens(JWT)。以下是一个简单的例子:

首先,你需要将 jjwt 库添加到你的项目中。如果使用 Maven,可以在 pom.xml 文件中添加以下依赖:

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-api</artifactId>
    <version>0.11.2</version>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-impl</artifactId>
    <version>0.11.2</version>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-jackson</artifactId>
    <version>0.11.2</version>
    <scope>runtime</scope>
</dependency>

然后,你可以使用以下Java代码生成JWT:

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

import java.util.Date;

public class JwtGenerator {
    
    

    public static void main(String[] args) {
    
    
        // 构建头部
        String algorithm = SignatureAlgorithm.HS256.getJcaName();
        String header = "{\"alg\":\"" + algorithm + "\",\"typ\":\"JWT\"}";

        // 构建载荷
        String subject = "1234567890";  // 主体标识
        String name = "John Doe";
        long nowMillis = System.currentTimeMillis();
        Date iat = new Date(nowMillis);  // 签发时间(当前时间)

        // 选择密钥
        String secretKey = "yourSecretKey";

        // 生成JWT
        String token = Jwts.builder()
                .setHeader(header)
                .setSubject(subject)
                .claim("name", name)
                .setIssuedAt(iat)
                .signWith(SignatureAlgorithm.HS256, secretKey)
                .compact();

        System.out.println(token);
    }
}

请确保替换示例中的密钥和其他参数为你实际的值。这个例子中使用了 HMAC SHA-256 算法,但你可以根据需求选择其他算法。在实际应用中,密钥应该是安全的,并且可能需要使用环境变量或其他方式来管理。

还有那些库

除了 io.jsonwebtoken,还有一些其他常用的Java库可以用于生成和处理JSON Web Tokens(JWT)。以下是一些常见的JWT库:

  1. Nimbus JOSE + JWT:
    在这里插入图片描述

    • 官方网站: Nimbus JOSE + JWT
    • 主要功能:
      • 提供了处理JOSE(JSON Object Signing and Encryption)和JWT的Java库。
      • 支持各种JWT相关的标准和规范,如JWT、JWS(JSON Web Signature)、JWE(JSON Web Encryption)等。
      • 提供了易于使用的API,支持生成和验证JWT。
  2. Java-JWT:
    在这里插入图片描述

    • GitHub地址: Java-JWT
    • 主要功能:
      • Auth0开发的Java库,用于生成和验证JWT。
      • 支持标准的JWT算法,如HMAC SHA256、RS256等。
      • 提供了简洁的API,适用于各种JWT用例。
  3. JJWT:
    在这里插入图片描述

    • GitHub地址: JJWT
    • 主要功能:
      • 一个简单的Java库,用于生成、解析和验证JWT。
      • 支持各种算法,包括HMAC SHA256、RS256等。
      • 提供了流畅的API,易于使用。
        当然,还有HuTool工具类,就不多赘述了
        在这里插入图片描述

选择使用哪个库取决于你的具体需求、项目的特点以及个人偏好。在使用之前,请仔细查阅相关文档,了解库的功能、性能和安全性。

JWT的解析和验证

解析和验证 JSON Web Tokens(JWT)通常包括以下步骤:

  1. 拆分 JWT: JWT 由三部分组成,分别是头部(Header)、载荷(Payload)、签名(Signature),它们之间用点号分隔。首先,将 JWT 字符串拆分成这三个部分。

  2. 解码 Base64: 对头部和载荷进行 Base64 解码,得到 JSON 字符串。

  3. 解析 JSON: 将解码后的头部和载荷 JSON 字符串解析为 JSON 对象。

  4. 验证签名(可选): 如果 JWT 使用签名算法进行签名,需要对头部、载荷和签名进行验证。验证的步骤通常包括获取密钥(对称或非对称密钥),使用相同的签名算法对头部和载荷进行签名,然后比较生成的签名与 JWT 中的签名是否匹配。

以下是一个使用 Java 的示例,使用 io.jsonwebtoken 库进行 JWT 解析和验证的过程:

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureException;

public class JwtParser {
    
    

    public static void main(String[] args) {
    
    
        // 要解析和验证的 JWT 字符串
        String jwtString = "yourJwtStringHere";

        try {
    
    
            // 解析 JWT
            Jws<Claims> jws = Jwts.parserBuilder()
                    .setSigningKey("yourSecretKey")  // 设置密钥
                    .build()
                    .parseClaimsJws(jwtString);

            // 获取载荷(Claims)
            Claims claims = jws.getBody();

            // 在此可以获取 JWT 中的信息,例如:
            String subject = claims.getSubject();
            String name = (String) claims.get("name");
            // 其他声明的获取方法...

            // 验证通过,可以继续处理业务逻辑
            System.out.println("JWT验证通过");

        } catch (ExpiredJwtException e) {
    
    
            // JWT 过期异常
            System.out.println("JWT已过期");
        } catch (SignatureException e) {
    
    
            // JWT 签名异常
            System.out.println("JWT签名验证失败");
        } catch (Exception e) {
    
    
            // 其他异常
            System.out.println("JWT解析失败");
        }
    }
}

请注意,上述代码中的密钥和其他参数需要根据你的实际情况进行调整。此外,对于非对称加密的情况,需要提供公钥进行验证。在实际应用中,也可以考虑使用库提供的更复杂的配置选项和错误处理机制。

猜你喜欢

转载自blog.csdn.net/weixin_53742691/article/details/134855465