SpringSecurity整合JWT

一、前言

  最近负责支付宝小程序后端项目设计,这里主要分享一下用户会话、接口鉴权的设计。参考过微信小程序后端的设计,会话需要依靠redis。相关的开发人员和我说依靠Redis并不是很靠谱,redis在业务高峰期不稳定,容易出现问题,总会出现用户会话丢失、超时的问题。之前听过JWT相关的设计,决定尝试一下。

二、什么是JWT

  JSON Web Token(JWT)是一个开放标准(RFC 7519),它定义了一种紧凑且独立的方式,用于在各方之间作为JSON对象安全地传输信息。此信息可以通过数字签名进行验证和信任。JWT可以使用秘密(使用HMAC算法)或使用RSA或ECDSA的公钥/私钥对进行签名。虽然JWT可以加密以在各方之间提供保密,但我们将专注于签名令牌。签名令牌可以验证其中包含的声明的完整性,而加密令牌则隐藏其他方的声明。当使用公钥/私钥对签名令牌时,签名还证明只有持有私钥的一方是签署它的一方。

  更多参考:Introduction to JSON Web Tokens

三、JWT优势

  JWT支持多种方式的信息加密,验证时并不需要依赖缓存。支持存储用户非敏感信息、超时、刷新等操作,JWT由前端在用户发送请求时自动放入header中,可以有效避免CSRF攻击,用来维护服务端和用户会话再好也不过了。

四、JWT工具类

public class JwtUtils {

    /**
     * 创建token
     *
     * @param claim  claim中为userId
     * @param secret 创建token密钥
     * @return token
     */
    public static String createToken(Map claim, String secret) {
        long expirationDate = AlipayServiceAppletConstants.EXPIRATION_DATE;
        LocalDateTime nowTime = LocalDateTime.now();
        return Jwts.builder().setClaims(claim)
                .setSubject("AlipayApplet") //设置token主题
                .setIssuedAt(localDateTimeToDate(nowTime)) //设置token发布时间
                .setExpiration(getExpirationDate(nowTime, expirationDate)) // 设置token过期时间
                .signWith(SignatureAlgorithm.HS512, secret)
                .compact();
    }

    /**
     * 将LocalDateTime转换为Date
     *
     * @param localDateTime
     * @return Date
     */
    public static Date localDateTimeToDate(LocalDateTime localDateTime) {
        ZoneId zoneId = ZoneId.systemDefault();
        ZonedDateTime zdt = localDateTime.atZone(zoneId);
        return Date.from(zdt.toInstant());
    }

    /**
     * 获取token过期的时间
     *
     * @param createTime       token创建时间
     * @param calendarInterval token有效时间间隔
     * @return
     */
    public static Date getExpirationDate(LocalDateTime createTime, long calendarInterval) {
        LocalDateTime expirationDate = createTime.plus(calendarInterval, ChronoUnit.MINUTES);
        return localDateTimeToDate(expirationDate);
    }


    /**
     * JWT  解析token是否正确
     *
     * @param token
     * @return
     * @throws Exception
     */
    public static Claims parseToken(String token) throws ExpiredJwtException {

        Claims claims = Jwts.parser()
                .setSigningKey(AlipayServiceAppletConstants.ALIPAY_APPLET_SECRET)
                .parseClaimsJws(token)
                .getBody();

        return claims;

    }

    /**
     * token 刷新:
     * 1.小于TIME_OUT直接通过;
     * 2.大于TIME_OUT 小于FORBID_REFRES_HTIME需要刷新;
     * 3.超过FORBID_REFRES_HTIME 直接返回禁用刷新;
     *
     * @param oldToken
     * @return
     */
    public static String refresh(String oldToken) {
        long tokenDurationTime = AlipayServiceAppletConstants.EXPIRATION_DATE;//token持续时间/分钟
        long tokenRefreshDurationTime = AlipayServiceAppletConstants.ALIPAY_APPLET_FORBID_REFRES_HTIME;//token允许刷新时间/分钟

        try {
            getExpirationDate(oldToken);
        } catch (ExpiredJwtException e) {
            try {
                long expirationTime = TimeUnit.MINUTES.convert(e.getClaims().getExpiration().toInstant().getEpochSecond(), TimeUnit.SECONDS);
                long nowTime = TimeUnit.MINUTES.convert(Instant.now().getEpochSecond(), TimeUnit.SECONDS);
                long tokenTimeout = nowTime - expirationTime;

                /*2.大于TIME_OUT 小于FORBID_REFRES_HTIME需要刷新*/
                if (tokenTimeout >= tokenDurationTime &
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值