package org.springblade.auth.utils;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.SignatureException;
import org.springframework.security.oauth2.common.exceptions.UserDeniedAuthorizationException;

import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.util.Date;

public class JwtUtil {

    private static final String SECRET = "sbajhdbasjk342@ldhbasilheiuqwhei$Fu123y28db@iaSARFSRFAXSksZSXb%dkaSADaSSAsb";
    private static final Key signingKey = new SecretKeySpec(SECRET.getBytes(StandardCharsets.UTF_8),
            SignatureAlgorithm.HS256.getJcaName());

    /**
     * 生成token
     *
     * @param obj 加密对象
     * @return token
     */
    public static String generateToken(Object obj) {
        // 这里其实就是new一个JwtBuilder，设置jwt的body
        JwtBuilder jwtBuilder = Jwts.builder()
                // 设置JwtId：是JWT的唯一标识，根据业务需要，这个可以设置为一个不重复的值，主要用来作为一次性token,从而回避重放攻击。
                .setId(IdWorker.getIdStr())
                // 设置发送内容
                .setSubject(JSONObject.toJSONString(obj))
                // 签发时间
                .setIssuedAt(new Date())
                // 设置过期时间
                .setExpiration(getExpiration())
                // 签名
                .signWith(signingKey);

        // 根据对象生成 令牌token
        return jwtBuilder.compact();
    }

    /**
     * 解析token
     *
     * @param token  token
     * @param tClass 反序列化对象
     */
    public static <T> T parseToken(String token, Class<T> tClass) {
        try {
            Claims claims = Jwts.parserBuilder().setSigningKey(signingKey).build().parseClaimsJws(token).getBody();
            return JSONObject.parseObject(claims.getSubject(), tClass);
        } catch (ExpiredJwtException expiredJwtException) {
            throw new UserDeniedAuthorizationException("token已过期");
        } catch (SignatureException signatureException) {
            throw new UserDeniedAuthorizationException("密钥错误");
        } catch (MalformedJwtException malformedJwtException) {
            throw new UserDeniedAuthorizationException("密钥算法，或者密钥转换错误，或者token不正确");
        } catch (MissingClaimException missingClaimException) {
            throw new UserDeniedAuthorizationException("密钥缺少校验数据");
        } catch (JwtException jwtException) {
            throw new UserDeniedAuthorizationException("密钥解析错误");
        }
    }

    /**
     * 设置过期时间
     * <p>
     * 60秒后过期
     */
    static private Date getExpiration() {
        return new Date(System.currentTimeMillis() + 60 * 1000);
    }

}



