JwtTokenUtil.java 4.89 KB
package isa.qa.utils;

import io.jsonwebtoken.*;
import isa.qa.core.AuthenticationFailedException;
import isa.qa.properties.JwtProperties;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * JSON WEB TOKEN 工具类
 *
 * @author May
 * @version 1.0
 * @date 2018/5/6 14:40
 */
@Component
@AllArgsConstructor
public class JwtTokenUtil {

    private static final String CLAIM_KEY_USERNAME = "sub";
    private static final String CLAIM_KEY_CREATED = "created";

    private final JwtProperties jwtProperties;

    /**
     * 从Token中解析出App key
     *
     * @param token token值
     */
    public String getAppKeyFromToken(String token) throws AuthenticationFailedException {
        String username;
        final Claims claims = getClaimsFromToken(token);
        username = claims.getSubject();

        return username;
    }

    /**
     * 从Token从解析出Token的生成日期
     *
     * @param token 原始token
     */
    public Date getCreatedDateFromToken(String token) throws AuthenticationFailedException {
        Date created;
        final Claims claims = getClaimsFromToken(token);
        created = new Date((Long) claims.get(CLAIM_KEY_CREATED));

        return created;
    }

    /**
     * 利用JWT及设置的过期时长从Token中计算出过期的时间
     *
     * @param token 原始token
     */
    public Date getExpirationDateFromToken(String token) throws AuthenticationFailedException {
        Date expiration;
        final Claims claims = getClaimsFromToken(token);
        expiration = claims.getExpiration();

        return expiration;
    }

    /**
     * 从token中解析出所有的相关的参数
     */
    private Claims getClaimsFromToken(String token) throws AuthenticationFailedException {
        Claims claims;
        try {
            claims = Jwts.parser()
                    .setSigningKey(jwtProperties.getSecret())
                    .parseClaimsJws(token)
                    .getBody();
        } catch (ExpiredJwtException e) {
            throw new AuthenticationFailedException("登录凭证失效了,请重新登录");
        } catch (SignatureException e) {
            throw new AuthenticationFailedException("登录凭证有误");
        }

        return claims;
    }

    /**
     * 计算得到的即刻生成的Token的过期时间
     */
    private Date generateExpirationDate(Integer hours) {
        return new Date(System.currentTimeMillis() + (hours * 3600) * 1000);
    }

    /**
     * 校验token是否过期了
     *
     * @param token 校验的token
     */
    private Boolean isTokenExpired(String token) throws AuthenticationFailedException {
        final Date expiration = getExpirationDateFromToken(token);
        return expiration.before(new Date());
    }

    /**
     * 判断Token是否是在上次密码变更前所生成的
     *
     * @param created 创建时间
     * @param lastPasswordReset 上次密码重置时间
     */
    private Boolean isCreatedBeforeLastPasswordReset(Date created, Date lastPasswordReset) {
        return (lastPasswordReset != null && created.before(lastPasswordReset));
    }

    /**
     * 设置生成Token的组合参数
     *
     * @param userDetails 用户信息
     */
    public String generateToken(String appKey, Integer hours) {
        Map<String, Object> claims = new HashMap<>(2);
        claims.put(CLAIM_KEY_USERNAME, appKey);
        claims.put(CLAIM_KEY_CREATED, new Date());
        return generateToken(claims, hours);
    }

    /**
     * 根据组合参数生成Token
     *
     * @param claims 组合参数
     * @param hours
     */
    String generateToken(Map<String, Object> claims, Integer hours) {
        return Jwts.builder()
                .setClaims(claims)
                .setExpiration(generateExpirationDate(hours))
                .signWith(SignatureAlgorithm.HS512, jwtProperties.getSecret())
                .compact();
    }

    /**
     * 根据Token是否是上次密码更换前所生成的来决定Token是否可以刷新
     *
     * @param token 原始token
     * @param lastPasswordReset 上次更新密码时间
     */
    public Boolean canTokenBeRefreshed(String token, Date lastPasswordReset)
            throws AuthenticationFailedException {
        final Date created = getCreatedDateFromToken(token);
        return !isCreatedBeforeLastPasswordReset(created, lastPasswordReset)
                && !isTokenExpired(token);
    }

    /**
     * 通过解析原始token换取新的token
     *
     * @param token 原始token
     */
    public String refreshToken(String token, Integer hours) throws AuthenticationFailedException {
        String refreshedToken;
        final Claims claims = getClaimsFromToken(token);
        claims.put(CLAIM_KEY_CREATED, new Date());
        refreshedToken = generateToken(claims, hours);

        return refreshedToken;
    }
}