天天看点

JWT 详解

定义:JSON Web Token(缩写 JWT)是目前最流行的跨域认证解决方案

由于HTTP协议是无状态的,这意味着如果我们想判定一个接口是否被认证后访问,就需要借助cookie或者session会话机制进行判定,但是由于现在的系统架构大部分都不止一台服务器,此时又要借助数据库或者全局缓存 做存储,这种方案显然受限太多。

那么我们可不可以让认证令牌的发布者自己去识别这个令牌是不是我曾经发布的令牌呢(JWT核心思想),这是JWT最大的优点也是最大的缺点,优点是简单快捷、不需要依赖任何第三方操作就能实现身份认证,缺点就是对于任何拥有用户发布令牌的请求都会认证通过。

 JWT 数据结构(三部分)

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1OTkxMjAxMTgsInVzZXJuYW1lIjoibHhxIn0.YiFRESjiBc8oQuAiGo43MA1AJ2iDFJYO8AYlaor5w2w

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

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

alg

属性表示签名的算法(algorithm),默认是 HMAC SHA256(写成 HS256);

typ

属性表示这个令牌(token)的类型(type),JWT 令牌统一写为

JWT

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

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

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

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

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

 算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用"点"(

.

)分隔,就可以返回给用户。

Maven依赖

<dependency>
  <groupId>com.auth0</groupId>
  <artifactId>java-jwt</artifactId>
 <version>3.5.0</version>
 </dependency>
           
**
 * @Description:
 * @Author: Lxq
 * @Date: 2019/9/6 12:25
 */
public class JwtUtil {

    /**
     * 设置token的失效时间(7天)
     */
    private static final long EXPIRE_TIME = 7 * 24 * 60 * 60 * 1000;

    /**
     * 校验token是否正确,是否过期
     *
     * @param token    密钥
     * @param username 用户名
     * @param secret   密码
     * @return 是否正确
     */
    public static boolean verify(String token, String username, String secret) {
        try {
            //根据密码生成JWT效验器
            Algorithm algorithm = Algorithm.HMAC256(secret);
            JWTVerifier verifier = JWT.require(algorithm)
                    .withClaim("username", username)
                    .build();
            //效验TOKEN
            DecodedJWT jwt = verifier.verify(token);
            return true;
        } catch (Exception exception) {
            return false;
        }
    }

    /**
     * 获得token中的信息无需secret解密也能获得
     *
     * @return token中包含的用户名
     */
    public static String getUsername(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim("username").asString();
        } catch (JWTDecodeException e) {
            return null;
        }
    }

    /**
     * 生成签名,7天后过期
     *
     * @param username 用户名
     * @param secret   用户的密码
     * @return 加密的token
     */
    public static String sign(String username, String secret) {
        Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
        Algorithm algorithm = Algorithm.HMAC256(secret);
        // 附带username信息
        return JWT.create()
                .withClaim("username", username)
                .withExpiresAt(date)
                .sign(algorithm);

    }
}