欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot無(wú)感刷新Token的實(shí)現(xiàn)示例

 更新時(shí)間:2025年07月21日 11:02:36   作者:星辰聊技術(shù)  
無(wú)感刷新Token避免會(huì)話過(guò)期導(dǎo)致數(shù)據(jù)丟失,通過(guò)后端動(dòng)態(tài)續(xù)簽或前端主動(dòng)請(qǐng)求,結(jié)合雙Token機(jī)制,實(shí)現(xiàn)身份憑證自動(dòng)更新,感興趣的可以了解一下

背景問(wèn)題:為什么需要無(wú)感刷新?

想象這樣一個(gè)場(chǎng)景:

“我正在后臺(tái)管理系統(tǒng)中錄入數(shù)據(jù),頁(yè)面突然跳轉(zhuǎn)回登錄界面,之前填寫的內(nèi)容全沒(méi)了!”

這是典型的 Token 到期導(dǎo)致會(huì)話失效 的問(wèn)題,尤其在使用 Redis 等緩存中間件存儲(chǔ) Token 時(shí)尤為常見(jiàn)。

問(wèn)題根源

后端通常通過(guò) JWT 來(lái)實(shí)現(xiàn)無(wú)狀態(tài)身份驗(yàn)證,但 JWT 的缺陷也很明顯:過(guò)期即失效,無(wú)法修改或撤銷。如果不設(shè)計(jì) Token 刷新機(jī)制,用戶體驗(yàn)將大打折扣。

核心策略:Token 無(wú)感續(xù)簽方案概述

方案一:后端自動(dòng)續(xù)期(推薦)

在每次用戶請(qǐng)求時(shí),后端檢查當(dāng)前 Token 的有效時(shí)間:

  • 若臨近過(guò)期(如小于5分鐘) ,則動(dòng)態(tài)生成一個(gè)新 Token,加入響應(yīng)頭中返回;
  • 前端攔截響應(yīng)頭,若發(fā)現(xiàn)新的 Token,與本地不一致則自動(dòng)更新本地 Token。

方案二:前端主動(dòng)續(xù)簽(補(bǔ)充方案)

  • 前端維護(hù)一對(duì) Token:access_token(短期)+ refresh_token(長(zhǎng)期);
  • 每隔一段時(shí)間,前端使用 refresh_token 去調(diào)用刷新接口,獲取新的 access_token。

后端實(shí)現(xiàn)細(xì)節(jié)

依賴配置(pom.xml)

<dependencies>
    <dependency>
        <groupId>cn.hutool</groupId>
        <artifactId>hutool-all</artifactId>
        <version>5.5.1</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.33</version>
    </dependency>
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt</artifactId>
        <version>0.9.1</version>
    </dependency>
</dependencies>

JWT 工具類JwtUtil.java

 代碼路徑:/src/main/java/com/demo/auth/utils/JwtUtil.java

package com.demo.auth.utils;


import io.jsonwebtoken.*;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.*;


public class JwtUtil {
    public static final long JWT_TTL = 1000L * 60 * 60 * 24; // 24小時(shí)
    public static final String JWT_KEY = "qx";


    public static String createJWT(String subject) {
        return getJwtBuilder(subject, null, UUID.randomUUID().toString().replace("-", "")).compact();
    }


    public static String createJWT(String subject, Long ttlMillis) {
        return getJwtBuilder(subject, ttlMillis, UUID.randomUUID().toString()).compact();
    }


    private static JwtBuilder getJwtBuilder(String subject, Long ttlMillis, String uuid) {
        long nowMillis = System.currentTimeMillis();
        long expMillis = (ttlMillis != null ? nowMillis + ttlMillis : nowMillis + JWT_TTL);
        SecretKey secretKey = generalKey();
        return Jwts.builder()
                .setId(uuid)
                .setSubject(subject)
                .setIssuer("icoderoad")
                .setIssuedAt(new Date(nowMillis))
                .setExpiration(new Date(expMillis))
                .signWith(SignatureAlgorithm.HS256, secretKey);
    }


    public static Claims parseJWT(String jwt) throws Exception {
        return Jwts.parser()
                .setSigningKey(generalKey())
                .parseClaimsJws(jwt)
                .getBody();
    }


    public static SecretKey generalKey() {
        byte[] key = Base64.getDecoder().decode(JWT_KEY);
        return new SecretKeySpec(key, 0, key.length, "AES");
    }


    public static Date getExpiration(String jwt) {
        try {
            return parseJWT(jwt).getExpiration();
        } catch (Exception e) {
            throw new RuntimeException("Token 解析失敗", e);
        }
    }
}

Token 攔截與續(xù)簽邏輯

 攔截器路徑:/src/main/java/com/demo/auth/interceptor/AuthInterceptor.java

public class AuthInterceptor implements HandlerInterceptor {


    private static final long REFRESH_THRESHOLD = 1000L * 60 * 5; // 剩余5分鐘內(nèi)刷新


    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {


        String token = request.getHeader("Authorization");
        if (StringUtils.isEmpty(token)) {
            throw new RuntimeException("未登錄");
        }


        Claims claims = JwtUtil.parseJWT(token);
        long now = System.currentTimeMillis();
        long exp = claims.getExpiration().getTime();


        if (exp - now < REFRESH_THRESHOLD) {
            String newToken = JwtUtil.createJWT(claims.getSubject());
            response.setHeader("X-Token-Refresh", newToken);
        }


        return true;
    }
}

前端處理邏輯(以 Vue + Axios 為例)

前端攔截代碼:

axios.interceptors.response.use(response => {
    const newToken = response.headers['x-token-refresh'];
    if (newToken && newToken !== localStorage.getItem('access_token')) {
        localStorage.setItem('access_token', newToken);
    }
    return response;
}, error => {
    // 處理401
    if (error.response.status === 401) {
        // 可以保存草稿后跳轉(zhuǎn)登錄
    }
    return Promise.reject(error);
});

關(guān)于 AccessToken 和 RefreshToken 的機(jī)制說(shuō)明

類型用途特點(diǎn)
AccessToken攜帶用戶身份,頻繁使用安全風(fēng)險(xiǎn)高,需短時(shí)過(guò)期
RefreshToken用于續(xù)簽 AccessToken不暴露給前端,一般保存在 Cookie 或 HttpOnly

標(biāo)準(zhǔn)雙 Token 模式提升了安全性和用戶體驗(yàn),避免因 AccessToken 頻繁刷新帶來(lái)的資源浪費(fèi)。

特別討論:表單靜默超時(shí)的處理策略

場(chǎng)景問(wèn)題:

用戶長(zhǎng)時(shí)間填寫表單,沒(méi)有發(fā)出任何請(qǐng)求,點(diǎn)擊提交時(shí)發(fā)現(xiàn) token 已失效,被重定向到登錄頁(yè),數(shù)據(jù)全丟。

推薦方案:

  • 提交失敗后前端本地緩存表單數(shù)據(jù);
  • 登錄成功后回顯草稿,確保用戶體驗(yàn)不受損;
  • 或者在用戶輸入行為時(shí)定期心跳請(qǐng)求,觸發(fā)后端續(xù)簽。

總結(jié)

實(shí)現(xiàn)無(wú)感刷新 Token,是用戶體驗(yàn)與安全性協(xié)同優(yōu)化的重要實(shí)踐。通過(guò)后端智能判斷與前端攔截配合,結(jié)合雙 Token 模式或動(dòng)態(tài)續(xù)簽機(jī)制,我們可以實(shí)現(xiàn):

用戶操作不中斷 身份憑證自動(dòng)續(xù)期 安全控制粒度更靈活

到此這篇關(guān)于SpringBoot無(wú)感刷新Token的實(shí)現(xiàn)示例的文章就介紹到這了,更多相關(guān)SpringBoot無(wú)感刷新Token內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Mybatis Generator具體使用小技巧

    Mybatis Generator具體使用小技巧

    本文主要介紹了Mybatis Generator具體使用小技巧,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-12-12
  • 基于Graphics2D drawImage圖片失真的解決方案

    基于Graphics2D drawImage圖片失真的解決方案

    這篇文章主要介紹了基于Graphics2D drawImage圖片失真的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • Java三種獲取redis的連接及redis_String類型演示(適合新手)

    Java三種獲取redis的連接及redis_String類型演示(適合新手)

    這篇文章主要介紹了Java三種獲取redis的連接及redis_String類型演示(適合新手),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • SpringBoot快速過(guò)濾出一次請(qǐng)求的所有日志的示例代碼

    SpringBoot快速過(guò)濾出一次請(qǐng)求的所有日志的示例代碼

    在現(xiàn)網(wǎng)出現(xiàn)故障時(shí),我們經(jīng)常需要獲取一次請(qǐng)求流程里的所有日志進(jìn)行定位,本文給大家介紹了SpringBoot如何快速過(guò)濾出一次請(qǐng)求的所有日志,文中有相關(guān)的代碼和示例供大家參考,需要的朋友可以參考下
    2024-03-03
  • java語(yǔ)言如何生成plist下載ipa文件

    java語(yǔ)言如何生成plist下載ipa文件

    這篇文章主要介紹了java語(yǔ)言如何生成plist下載ipa文件問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • mybatis?plus配置自動(dòng)create_time和update_time方式

    mybatis?plus配置自動(dòng)create_time和update_time方式

    在處理數(shù)據(jù)時(shí),注意時(shí)間類型的轉(zhuǎn)換非常重要,不同編程環(huán)境和數(shù)據(jù)庫(kù)對(duì)時(shí)間數(shù)據(jù)的處理方式各異,因此在數(shù)據(jù)遷移或日常處理中需謹(jǐn)慎處理時(shí)間格式,個(gè)人經(jīng)驗(yàn)表明,了解常用的時(shí)間轉(zhuǎn)換函數(shù)和方法能有效避免錯(cuò)誤,提高工作效率,希望這些經(jīng)驗(yàn)?zāi)転榇蠹規(guī)?lái)幫助
    2024-09-09
  • Java使用JSONObject操作json實(shí)例解析

    Java使用JSONObject操作json實(shí)例解析

    這篇文章主要介紹了Java使用JSONObject操作json,結(jié)合實(shí)例形式較為詳細(xì)的分析了Java使用JSONObject解析json數(shù)據(jù)相關(guān)原理、使用技巧與操作注意事項(xiàng),需要的朋友可以參考下
    2020-04-04
  • jasypt-spring-boot-starter實(shí)現(xiàn)加解密和數(shù)據(jù)返顯方式

    jasypt-spring-boot-starter實(shí)現(xiàn)加解密和數(shù)據(jù)返顯方式

    這篇文章主要介紹了jasypt-spring-boot-starter實(shí)現(xiàn)加解密和數(shù)據(jù)返顯方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-05-05
  • Spring中@PropertySource注解使用場(chǎng)景解析

    Spring中@PropertySource注解使用場(chǎng)景解析

    這篇文章主要介紹了Spring中@PropertySource注解使用場(chǎng)景解析,@PropertySource注解就是Spring中提供的一個(gè)可以加載配置文件的注解,并且可以將配置文件中的內(nèi)容存放到Spring的環(huán)境變量中,需要的朋友可以參考下
    2023-11-11
  • java持久層框架mybatis防止sql注入的方法

    java持久層框架mybatis防止sql注入的方法

    下面小編就為大家?guī)?lái)一篇java持久層框架mybatis防止sql注入的方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-10-10

最新評(píng)論