令牌技术 JWT令牌

1. 令牌(Token)

令牌(Token)是计算机安全领域中的一种凭证机制,用于验证用户身份或授权访问资源。它通常是一个字符串,携带了用户身份、权限或其他关键信息,服务端可通过验证令牌的合法性来判断请求的合法性。

常见令牌类型:

  • 会话令牌(Session Token):传统 Web 应用中,服务器生成一个唯一 ID 存储在服务端(如内存或数据库),客户端通过 Cookie 或 URL 参数携带该 ID。
  • 访问令牌(Access Token):如 OAuth 2.0 中的令牌,用于授权第三方应用访问用户资源。
  • JWT(JSON Web Token):一种自包含的令牌标准,无需服务端存储,直接通过签名验证合法性。

2. JWT令牌

2.1 JWT的组成结构

JWT 由三部分组成,格式为:Header.Payload.Signature,每部分通过 Base64Url 编码后拼接而成。

组成:

  • 第一部分:Header(头部),声明令牌类型和签名算法。
  • 第二部分:Payload(有效载荷),携带一些自定义信息、默认信息等(称为声明,Claims)。
    • 声明类型:
      • 预定义声明(Registered Claims):如 iss(签发者)、exp(过期时间)、sub(用户标识)。
      • 自定义声明(Public/Private Claims):如 userIdrole
  • 第三部分:Signature(签名),防止令牌被篡改、确保安全性。将header、payload融入,并指定密钥,通过指定签名算法计算而来。
    • ​​​​​​​​​​​生成方式:使用 Header 中指定的算法,对 Header + "." + Payload 进行签名。

2.2 JWT的核心特性

  1. 自包含性:所有必要信息(如用户身份、权限)直接存储在令牌中。
  2. 无状态性:服务端无需存储会话信息,适合分布式系统。
  3. 签名防篡改:通过签名确保数据完整性。

2.3 JWT的工作流程

  1. 用户登录:客户端提交用户名密码。
  2. 生成 JWT:服务端验证身份后,生成并返回 JWT。
  3. 携带令牌:客户端将 JWT 存储在本地(如 LocalStorage 或 Cookie),并在请求头中携带:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
  1. 验证令牌:服务端验证签名和有效期,并解析数据授权访问。

2.4 示例代码(java + jjwt库)

生成jwt

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;

public class JwtGenerator {
    private static final String SECRET_KEY = "your-256-bit-secret"; // 密钥需足够复杂

    public static String createJwt() {
        return Jwts.builder()
                .setSubject("user123")                 // 用户标识
                .claim("name", "Alice")                // 自定义声明
                .claim("role", "admin")
                .setIssuedAt(new Date())               // 签发时间
                .setExpiration(new Date(System.currentTimeMillis() + 3600000)) // 1小时后过期
                .signWith(SignatureAlgorithm.HS256, SECRET_KEY)
                .compact();  //生成令牌
    }

    public static void main(String[] args) {
        String jwt = createJwt();
        System.out.println("JWT: " + jwt);
    }
}

验证并解析jwt

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.SignatureException;

public class JwtParser {
    private static final String SECRET_KEY = "your-256-bit-secret";

    public static void parseJwt(String jwt) {
        try {
            Claims claims = Jwts.parser()
                    .setSigningKey(SECRET_KEY)
                    .parseClaimsJws(jwt)
                    .getBody();

            System.out.println("Subject: " + claims.getSubject());
            System.out.println("Name: " + claims.get("name"));
            System.out.println("Expiration: " + claims.getExpiration());
        } catch (SignatureException e) {
            System.err.println("无效签名!令牌可能被篡改。");
        } catch (ExpiredJwtException e) {
            System.err.println("令牌已过期!");
        }
    }

    public static void main(String[] args) {
        String jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."; // 替换为实际 JWT
        parseJwt(jwt);
    }
}

你可能感兴趣的:(数据库)