JWT结构及io.jsonwebtoken.jjwt工具使用

JsonWebToken介绍

JsonWebToken(简称JWT)是实现token技术的一种解决方案,它包含三部分,分别是: 头部(header ),载荷(payload ),签名 (signature)

他们按照 A.B.C 的格式拼接起来,其中C由A和B生成,他们之间的格式为 Base64(header).Base64(payload).H256(A.B)(也可以使用不同的签名算法,默认情况下是HS256)。需要注意的是header和payload都是使用Base64URL算法对象序列化之后的字符串.

名词解释:

HS256: HMACSHA256,一种消息摘要算法
Base64URL: Base64中用的三个字符是"+""/""=",由于在URL中有特殊含义,因此Base64URL中对他们做了替换:"="去掉,"+""-"替换,"/""_"替换,这就是Base64URL算法。

结构

头部(header)

Header 部分是一个 JSON 对象,描述 JWT 的元数据,一般很少改动直接使用默认的即可

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

alg属性表示签名的算法(algorithm);typ属性表示这个令牌(token)的类型(type),JWT 令牌统一写为JWT

载荷(playload)

Payload 部分也是一个 JSON 对象,用来存放实际需要传递的数据。

可自行指定字段,很灵活,也有固定字段表示特定含义(但不一定要包含特定字段,只是推荐)。下面是官方推荐的字段:

{
    "iss": "签发者",
    "sub": "当前令牌的描述说明",
    "aud": "接收方",
    "exp": "过期时间",
    "iat": "创建时间",
    "nbf": "在什么时间之前,该Token不可用",
    "jti": "Token唯一标识"
}

下面就是一个例子:

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

签名(signature)

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

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

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

密钥在摘要算法中起盐值的作用。

算出签名以后,将header和payload用Base64URL算法对象序列化,然后把这三部分用“.”拼接起来就是生成的token了。

io.jsonwebtoken.jjwt工具使用

maven依赖:

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

下面是一个示例工具类:

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;

/**
 * @author
 */
public class JwtUtils {

    //过期时间
    public static final long EXPIRE = 1000 * 60 * 60 * 24;
    //签名密钥
    public static final String SECRET = "ukc8BDbRigUDaY6pZFfWus2jZWLPHO";

    /**
    * 使用用户id和nickname获取一个token字符串
    */
    public static String getJwtToken(String id, String nickname){

        //使用builder构造一个JwtToken
        String JwtToken = Jwts.builder()
                //头部信息
                .setHeaderParam("typ", "JWT")
                .setHeaderParam("alg", "HS256")
                //载荷中的推荐信息
                .setSubject("guli-user")
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRE))
                //载荷中的自定义信息
                .claim("id", id)
                .claim("nickname", nickname)
                //签名
                .signWith(SignatureAlgorithm.HS256, SECRET)
                //Base64URL前两部分并连接签名,获取token
                .compact();

        return JwtToken;
    }

    /**
     * 判断传入的token字符串是否存在与有效
     */
    public static boolean checkToken(String jwtToken) {
        if(StringUtils.isEmpty(jwtToken)) return false;
        try {
            //使用parser解析jwt信息
            Jwts.parser().setSigningKey(SECRET).parseClaimsJws(jwtToken);
        //如果格式不对,会抛出UnsupportedJwtException异常
        //如果验证签名失败,会抛出SignatureException异常
        //如果token过期,会抛出ExpiredJwtException异常
        //如果字符串为空,会抛出IllegalArgumentException异常
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 判断HttpServletRequest中头部携带的token是否存在与有效
     */
    public static boolean checkToken(HttpServletRequest request) {
        try {
            String jwtToken = request.getHeader("token");
            if(StringUtils.isEmpty(jwtToken)) return false;
            Jwts.parser().setSigningKey(SECRET).parseClaimsJws(jwtToken);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 根据token获取用户id
     * @param request
     * @return
     */
    public static String getMemberIdByJwtToken(HttpServletRequest request) {
        String jwtToken = request.getHeader("token");
        if(StringUtils.isEmpty(jwtToken)) return "";
        Jws<Claims> claimsJws = Jwts.parser().setSigningKey(SECRET).parseClaimsJws(jwtToken);
        //getBody获取用户在载荷中定义的信息
        Claims claims = claimsJws.getBody();
        return (String)claims.get("id");
    }
}

原创文章,作者:彭晨涛,如若转载,请注明出处:https://www.codetool.top/article/jwt%e7%bb%93%e6%9e%84%e5%8f%8aio-jsonwebtoken-jjwt%e5%b7%a5%e5%85%b7%e4%bd%bf%e7%94%a8/

发表评论

电子邮件地址不会被公开。