package com.kxs.adminap.util;

 
import io.jsonwebtoken.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
 
import javax.crypto.spec.SecretKeySpec;
import java.security.Key;
import java.util.Base64;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
 
/**
 * JWT 工具类
 * <p>
 * jwt含有三部分：头部（header）、载荷（payload）、签证（signature）
 * (1)头部一般有两部分信息：声明类型、声明加密的算法（通常使用HMAC SHA256）
 * (2)载荷该部分一般存放一些有效的信息。jwt的标准定义包含五个字段：
 * - iss：该JWT的签发者
 * - sub: 该JWT所面向的用户
 * - aud: 接收该JWT的一方
 * - exp(expires): 什么时候过期，这里是一个Unix时间戳
 * - iat(issued at): 在什么时候签发的
 * (3)签证（signature） JWT最后一个部分。该部分是使用了HS256加密后的数据；包含三个部分
 *
 * @author kou
 */
@ConfigurationProperties(prefix = "custom.jwt")
@Component
public class JwtUtil {
 
    private static final Logger logger = LoggerFactory.getLogger(JwtUtil.class);
 
    // 秘钥
    private String secret = "aHR0cHM6Ly9teS5vc2NoaW5hLm5ldC91LzM2ODE4Njg=";
 
    // 有效时间
    private Long expire = 5184000L;
 
    // 用户凭证
    private String header = "token";
 
    // 签发者
    private String issuer = "kxs";

    public String getHeader() {
        return this.header;
    }
 
    /**
     * 生成token签名
     *
     * @param subject
     * @return
     */
    public String generateToken(String subject) {
 
        final SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
 
        Date now = new Date();
        // 过期时间
        Date expireDate = new Date(now.getTime() + expire * 1000);
 
        //Create the Signature SecretKey
        final byte[] apiKeySecretBytes = Base64.getEncoder().encode(secret.getBytes());
        final Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
 
        final Map<String, Object> headerMap = new HashMap<>();
        headerMap.put("alg", "HS256");
        headerMap.put("typ", "JWT");
 
        //add JWT Parameters
        final JwtBuilder builder = Jwts.builder()
                .setHeaderParams(headerMap)
                .setSubject(subject)
                .setIssuedAt(now)
                .setExpiration(expireDate)
                .setIssuer(issuer)
                .signWith(signatureAlgorithm, signingKey);
 
        logger.info("JWT[" + builder.compact() + "]");
        return builder.compact();
 
    }
 
    /**
     * 解析token
     *
     * @param token token
     * @return
     */
    public Claims parseToken(String token) {
 
        Claims claims = null;
        try {
            final byte[] apiKeySecretBytes = Base64.getEncoder().encode(secret.getBytes());
            claims = Jwts.parser().setSigningKey(apiKeySecretBytes).parseClaimsJws(token).getBody();
            logger.info("Parse JWT token by: ID: {}, Subject: {}, Issuer: {}, Expiration: {}", claims.getId(), claims.getSubject(), claims.getIssuer(), claims.getExpiration());
        } catch (ExpiredJwtException | UnsupportedJwtException | MalformedJwtException | SignatureException
                | IllegalArgumentException e) {
            logger.info("Parse JWT errror " + e.getMessage());
            return null;
        }
        return claims;
    }
 
    /**
     * 判断token是否过期
     *
     * @param expiration
     * @return
     */
    public boolean isExpired(Date expiration) {
 
        return expiration.before(new Date());
    }
 
}