您的位置 首页 java

JWT数据结构详解及Java工具类简单封装

JWT的数据结构

JWT是一个很长的字符串,中间用点(.)分隔成三个部分。

JWT的数据结构

示例:

  eyJhbGciOiJIUzUxMiJ9.eyJleHAiOjE2MTQyMzczNzQsImlhdCI6MTYxNDIzNzA3NH0.KgV4_BjO_fTYoqP2mmIhf3vA8cN2ml736aoLxYaxu6miwihYsbKXrvwClmoP3QVNXvIfGTen0eGqC3FYWoh1WA  

header

Header 部分是一个 JSON 对象,描述 JWT 的元数据,通常是下面的样子。

  {
   "alg": "HS256",
   "typ": "JWT"
 }  
  • alg属性:签名的算法(algorithm),默认是 HMAC SHA256(写成 HS256)
  • typ属性:这个令牌(token)的类型(type),JWT 令牌统一写为JWT。

Payload

Payload 部分也是一个 JSON 对象,用来存放实际需要传递的数据。JWT 规定了7个官方字段,供选用。

  • iss (issuer):签发人
  • exp (expiration time):过期时间
  • sub (subject):主题
  • aud (audience):受众
  • nbf (Not Before):生效时间
  • iat (Issued At):签发时间
  • jti (JWT ID):编号

除了官方字段,你还可以在这个部分定义私有字段,下面就是一个例子。

  {
   "sub": "1234567890",
   "name": "John Doe",
   "admin": true
 }  

注意,JWT 默认是不加密的,任何人都可以读到,所以不要把秘密信息放在这个部分。

Signature

Signature 部分是对前两部分的签名,防止数据篡改。

首先,需要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户。然后,使用 Header 里面指定的签名算法(默认是 HMAC SHA256),按照下面的公式产生签名。

  HMACSHA256(
   base64UrlEncode(header) + "." +
   base64UrlEncode(payload),
   secret)  

算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用”点”(.)分隔,就可以返回给用户。

JAVA 工具类封装

 import com.google.common.collect.Maps;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwt Exception ;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Date;
import java.util.Map;
import java.util.Objects;

public class TokenUtils {

     private   static  Logger LOGGER = LoggerFactory.getLogger(TokenUtils.class);

    /**
     * 签名密钥
     */
    private static final String SECRET = "mySecret";
    /**
     * 签发者
     */
    private static final String ISSUER = "jenny";
    /**
     * 过期时间:5分钟
     */
    private static Long expiration = new Long(300000);

    /**
     * 生成 Token
     */
    public static String generateToken(String username) {
        return generateToken(username, Maps.newHashMap());
    }

    /**
     * 生成 Token
     */
    public static String generateToken(String username,  Map <String, Object> claims) {
        return Jwts.builder()
                // 受众
                .setAudience(username)
                // 面向的用户
                .setSubject(username)
                // 签发者
                .setIssuer(ISSUER)
                .setClaims(claims)
                // 签发时间
                .setIssuedAt(new Date())
                // 过期时间
                .setExpiration(expiration())
                // 签名算法、签名密钥
                .signWith(SignatureAlgorithm.HS512, SECRET)
                .compact();
    }

    /**
     * 从 Token 中获取 username
     */
    public static String getUserCodeFromToken(String token) {
         String  userCode = "";
        try {
            final Claims claims = getClaimsFromToken(token);
            if (Objects.isNull(claims) || StringUtils.isEmpty(claims.getSubject())) {
                return userCode;
            }
            userCode = claims.getSubject();
        } catch (Exception e) {
            LOGGER.error("ger username from token error. ", e);
        }
        return userCode;
    }

    /**
     * 从 Token 中获取创建时间
     */
    public static Date getIssuedAt(String token) {
        Date issuedAt;
        try {
            final Claims claims = getClaimsFromToken(token);
            if (Objects.isNull(claims) || Objects.isNull(claims.getIssuedAt())) {
                return null;
            }
            issuedAt = claims.getIssuedAt();
        } catch (Exception e) {
            // TODO
            issuedAt = null;
        }
        return issuedAt;
    }

    /**
     * 从 Token 中获取过时时间
     */
    public static Date getExpiration(String token) {
        Date expiration;
        try {
            final Claims claims = getClaimsFromToken(token);
            if (Objects.isNull(claims) || Objects.isNull(claims.getExpiration())) {
                return null;
            }
            expiration = claims.getExpiration();
        } catch (Exception e) {
            // TODO
            expiration = null;
        }
        return expiration;
    }

    private static Claims getClaimsFromToken(String token) {
        Claims claims;
        try {
            claims = Jwts.parser()
                    .setSigningKey(SECRET)
                    .parseClaimsJws(token)
                    .getBody();
        } catch (Exception e) {
            if (e  instanceof  ExpiredJwtException) {
                throw new RuntimeException("TOKEN超时,请重新登录。");
            } else {
                LOGGER.error("解析Token信息时发生异常:", e);
                claims = null;
            }
        }
        return claims;
    }

    /**
     * 生成过期时间
     */
    private static Date expiration() {
        return new Date(System.currentTimeMillis() + expiration);
    }

    /**
     * 验证 Token 是否过期
     */
    private static  Boolean  isTokenExpired(String token) {
        final Date expiration = getExpiration(token);
        if (Objects.isNull(expiration)) {
            return true;
        }
        return expiration.before(new Date());
    }

}  

文章来源:智云一二三科技

文章标题:JWT数据结构详解及Java工具类简单封装

文章地址:https://www.zhihuclub.com/171177.shtml

关于作者: 智云科技

热门文章

网站地图