Jwt加解密

概述

记录jwt加解密的demo。
JSON Web Token (JWT) 是一种开放标准 (RFC 7519),用于在网络应用环境间安全地传输信息。JWT 通常用于身份验证和信息交换,因为它可以被签名和加密,确保数据的完整性和隐私性。

JWT 的基本结构

JWT 由三部分组成,每部分之间用点号(.)分隔:

  1. Header(头部)
  2. Payload(载荷)
  3. Signature(签名)

1. Header(头部)

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

示例:

{
  "alg": "HS256",
  "typ": "JWT"
}

2. Payload(载荷)

载荷部分包含声明(claims),声明是用来传递信息的键值对。JWT 规范定义了几种标准的声明,但你也可以自定义声明。

常见的标准声明包括:

  • iss (Issuer):签发者
  • sub (Subject):主题
  • aud (Audience):受众
  • exp (Expiration Time):过期时间
  • nbf (Not Before):生效时间
  • iat (Issued At):签发时间
  • jti (JWT ID):唯一标识符

示例:

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true,
  "userInfo": {
    "email": "john.doe@example.com",
    "roles": ["user", "admin"]
  },
  "iat": 1516239022
}

3. Signature(签名)

签名部分用于验证消息在传输过程中没有被篡改,并且可以验证 JWT 的接收方是否信任 JWT 的签发方。签名是通过对头部和载荷进行 Base64Url 编码,然后用指定的算法(如 HMAC SHA256)进行签名生成的。

签名生成步骤:

  1. 将头部和载荷分别进行 Base64Url 编码。
  2. 将编码后的头部和载荷用点号(.)连接起来。
  3. 使用指定的算法和密钥对连接后的字符串进行签名。

示例:

String encodedHeader = Base64Url.encode(headerJson);
String encodedPayload = Base64Url.encode(payloadJson);
String unsignedToken = encodedHeader + "." + encodedPayload;
String signature = sign(unsignedToken, secretKey);
String jwt = unsignedToken + "." + signature;

JWT 的优点

  1. 无状态:JWT 是无状态的,服务器不需要保存会话信息,可以轻松地扩展到多服务器架构。
  2. 安全性:JWT 可以被签名,确保数据的完整性;还可以被加密,确保数据的隐私性。
  3. 自包含:JWT 包含了所有的必要信息,可以在一个紧凑的字符串中传递。
  4. 跨域支持:JWT 可以在不同的域名之间传递,适用于单点登录(SSO)等场景。

JWT 的使用场景

  1. 身份验证:用户登录后,服务器生成一个 JWT 并返回给客户端。客户端在后续请求中携带 JWT,服务器验证 JWT 的有效性。
  2. 信息交换:在不同系统之间传递信息,确保信息的完整性和安全性。
  3. 授权:根据 JWT 中的声明信息,决定用户是否有权限访问特定资源。

引入依赖

      <dependency>
          <groupId>io.jsonwebtoken</groupId>
          <artifactId>jjwt</artifactId>
          <version>0.9.1</version>
      </dependency>

代码示例1

创建 JWT

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import javax.crypto.spec.SecretKeySpec;
import java.security.Key;
import java.util.Date;

public class JwtUtil {

    private static final String SECRET_KEY = "your-secret-key-must-be-at-least-512-bits-long"; // 确保密钥足够长

    public static String createToken(Map<String, Object> claims, long expiration) {
        Key signingKey = new SecretKeySpec(SECRET_KEY.getBytes("UTF-8"), SignatureAlgorithm.HS512.getJcaName());
        return Jwts.builder()
                .setClaims(claims)
                .setExpiration(new Date(System.currentTimeMillis() + expiration))
                .signWith(SignatureAlgorithm.HS512, signingKey)
                .compact();
    }
}

解析 JWT

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import javax.crypto.spec.SecretKeySpec;
import java.security.Key;
import java.util.Map;

public class JwtUtil {

    private static final String SECRET_KEY = "your-secret-key-must-be-at-least-512-bits-long"; // 确保密钥足够长

    public static Map<String, Object> parseToken(String token) {
        Key signingKey = new SecretKeySpec(SECRET_KEY.getBytes("UTF-8"), SignatureAlgorithm.HS512.getJcaName());
        Claims claims = Jwts.parser()
                .setSigningKey(signingKey)
                .parseClaimsJws(token)
                .getBody();
        return (Map<String, Object>) claims.get("userInfo");
    }
}

代码示例2

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import javax.crypto.spec.SecretKeySpec;
import java.security.Key;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;


public class UserInfo解析 {
    private static final String TOKEN_PREFIX = "Basic ";
    private static final String BASIC_TOKEN_KEY = "123456789poiuytrewqzxcvbnmlkjhgfdsa";
    
    /**
     * Token缺省过期时间是30分钟
     */
    private static final Long TOKEN_EXPIRATION = 1800000L;
    private static final String CLAIM_KEY_CREATEDTIME = "CreatedTime";
    private static final String USER_INFO_STRING = "userInfo";


    public static void main(String[] args) {
        Map<String, Object> map = new HashMap<>();
        Map<String, Object> userInfoMap = new HashMap<>();
        map.put("userInfo", userInfoMap);
        userInfoMap.put("name", "张三");
        userInfoMap.put("age", "26");
        userInfoMap.put("address", "河北石家庄");
        String token = encryptToken(map);
        Map<String, Object> userInfo = decryptToken(token);
        log.info(userInfo.toString());
    }

    public static Map<String, Object> decryptToken(String token){
        String jetToken = token.substring(TOKEN_PREFIX.length());
        Key signingKey = new SecretKeySpec(BASIC_TOKEN_KEY.getBytes(), SignatureAlgorithm.HS512.getJcaName());
        Claims claims = Jwts.parser().setSigningKey(signingKey).parseClaimsJws(jetToken).getBody();
        return claims.get(USER_INFO_STRING, Map.class);
    }

    public static String encryptToken(Map<String, Object> map){
        long createTime = System.currentTimeMillis();
        map.put(CLAIM_KEY_CREATEDTIME, createTime);
        String token = Jwts.builder()
                .setClaims(map)
                .setExpiration(new Date(createTime + TOKEN_EXPIRATION))
                .signWith(SignatureAlgorithm.HS512, BASIC_TOKEN_KEY.getBytes())
                .compact();
        return TOKEN_PREFIX + token;
    }

}

执行结果
在这里插入图片描述

注意事项

  1. 密钥管理:确保密钥的安全性,不要泄露。
  2. 过期时间:合理设置过期时间,防止 JWT 被长期滥用。
  3. 签名算法:选择合适的签名算法,确保安全性。
  4. 敏感信息:不要在 JWT 中存储敏感信息,如密码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值