chuck1in
11/3/2019 - 12:45 PM

TokenUtil

package com.llwx.common.utils;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;

import org.apache.commons.lang3.time.DateFormatUtils;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.llwx.common.bean.UserMerchantInfo;
import com.llwx.common.enums.ResponseCodeEnum;
import com.llwx.common.exceptions.BizCheckedException;

/**
 * tokenUtil
 *
 */
public class TokenUtil {

    private static final String SUB = "session";

    private static final String ISSUER = "llwx";

    private static final String PHONE = "phone";

    private static final String MERCHANT_ID = "merchant_id";

    /**
     * 校验 token 是否合法
     *
     * @param token token
     * @param secret 密钥
     */
    public static void verifyToken(String token, String secret) throws JWTVerificationException, BizCheckedException {
        try {
            Algorithm algorithm = Algorithm.HMAC256(secret);
            DecodedJWT decodeJwt = JWT.decode(token);
            String userId = decodeJwt.getAudience()
                                     .get(0);
            String phone = decodeJwt.getClaim(PHONE)
                                    .asString();
            String merchantId = decodeJwt.getClaim(MERCHANT_ID)
                                         .asString();
            // 校验签名是否符合客户端告知的用户信息
            JWTVerifier verifier = JWT.require(algorithm)
                                      .withIssuer(ISSUER)
                                      .withSubject(SUB)
                                      .withAudience(userId)
                                      .withClaim(PHONE, phone)
                                      .withClaim(MERCHANT_ID, merchantId)
                                      .build();
            DecodedJWT jwt = verifier.verify(token);
            Date expiresAt = jwt.getExpiresAt();
            String expiresAtStr = DateFormatUtils.ISO_8601_EXTENDED_DATETIME_TIME_ZONE_FORMAT.format(expiresAt);
            if (expiresAt.before(new Date())) {
                throw new BizCheckedException(ResponseCodeEnum.TOKEN_INVALID.getCode(),
                    String.format("用户 %s 的登录已过期。过期时间 %s", userId, expiresAtStr));
            }
        } catch (Exception e) {
            throw new BizCheckedException(e, ResponseCodeEnum.TOKEN_INVALID.getCode(),
                ResponseCodeEnum.TOKEN_INVALID.getMsg());
        }

    }

    public static UserMerchantInfo getUserMerchantInfo(String token) {
        String userId = getUserId(token);
        String phone = getPhone(token);
        String merchantId = getMerchantId(token);
        UserMerchantInfo userMerchantInfo = new UserMerchantInfo();
        userMerchantInfo.setMerchantId(merchantId);
        userMerchantInfo.setOpenId(userId);
        userMerchantInfo.setPhone(phone);
        return userMerchantInfo;
    }

    /**
     * 解析 token 获取用户 userId
     *
     * @param token tk
     * @return userId
     */
    public static String getUserId(String token) {
        DecodedJWT jwt = JWT.decode(token);
        return jwt.getAudience()
                  .get(0);
    }

    /**
     * 解析 token 获取用户 userId
     *
     * @param token tk
     * @return userId
     */
    public static String getPhone(String token) {
        DecodedJWT jwt = JWT.decode(token);
        return jwt.getClaim(PHONE)
                  .asString();
    }

    /**
     * 解析 token 获取用户 userId
     *
     * @param token tk
     * @return userId
     */
    public static String getMerchantId(String token) {
        DecodedJWT jwt = JWT.decode(token);
        return jwt.getClaim(MERCHANT_ID)
                  .asString();
    }

    /**
     * 创建 jwt token
     *
     * @param secret 密钥
     * @param outMinutes 过期时间
     * @return token
     */
    public static String createToken(String secret, long outMinutes, String userId, String phone, String merchantId) {
        Algorithm al = Algorithm.HMAC256(secret);
        Instant instant = LocalDateTime.now()
                                       .plusMinutes(outMinutes)
                                       .atZone(ZoneId.systemDefault())
                                       .toInstant();
        Date expire = Date.from(instant);
        return JWT.create()
                  .withIssuer(ISSUER)
                  .withSubject(SUB)
                  .withAudience(userId)
                  .withClaim(PHONE, phone)
                  .withClaim(MERCHANT_ID, merchantId)
                  .withExpiresAt(expire)
                  .sign(al);
    }
}