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

使用SpringBoot簡(jiǎn)單實(shí)現(xiàn)無(wú)感知的刷新 Token功能

 更新時(shí)間:2024年09月12日 08:29:46   作者:一只愛(ài)擼貓的程序猿  
實(shí)現(xiàn)無(wú)感知的刷新 Token 是一種提升用戶體驗(yàn)的常用技術(shù),可以在用戶使用應(yīng)用時(shí)自動(dòng)更新 Token,無(wú)需用戶手動(dòng)干預(yù),這種技術(shù)在需要長(zhǎng)時(shí)間保持用戶登錄狀態(tài)的應(yīng)用中非常有用,以下是使用Spring Boot實(shí)現(xiàn)無(wú)感知刷新Token的一個(gè)場(chǎng)景案例和相應(yīng)的示例代碼

引言

實(shí)現(xiàn)無(wú)感知的刷新 Token 是一種提升用戶體驗(yàn)的常用技術(shù),可以在用戶使用應(yīng)用時(shí)自動(dòng)更新 Token,無(wú)需用戶手動(dòng)干預(yù)。這種技術(shù)在需要長(zhǎng)時(shí)間保持用戶登錄狀態(tài)的應(yīng)用中非常有用,比如在一些需要頻繁訪問(wèn)服務(wù)器資源的WEB和移動(dòng)應(yīng)用。以下是使用Spring Boot實(shí)現(xiàn)無(wú)感知刷新Token的一個(gè)場(chǎng)景案例和相應(yīng)的示例代碼。

場(chǎng)景案例

假設(shè)我們有一個(gè)電子商務(wù)平臺(tái),用戶登錄后可以瀏覽商品、加入購(gòu)物車、提交訂單等。為了保持用戶會(huì)話的安全,我們使用JWT(JSON Web Tokens)技術(shù)。用戶的登錄會(huì)話由兩部分組成:access_tokenrefresh_token。access_token 有較短的有效期,例如15分鐘,而 refresh_token 有較長(zhǎng)的有效期,例如7天。

用戶每次發(fā)起請(qǐng)求時(shí),系統(tǒng)都會(huì)檢查 access_token 的有效性。如果 access_token 過(guò)期但 refresh_token 仍然有效,系統(tǒng)會(huì)自動(dòng)發(fā)起一個(gè)刷新令牌的過(guò)程,為用戶頒發(fā)新的 access_tokenrefresh_token,從而實(shí)現(xiàn)無(wú)感知刷新。

技術(shù)實(shí)現(xiàn)

我們將使用Spring Boot框架實(shí)現(xiàn)這一功能,具體技術(shù)棧包括:

  • Spring Boot 2.x
  • Spring Security for Authentication
  • JWT for token generation and validation
  • Maven for dependency management

示例代碼

1. 引入依賴

pom.xml 中添加以下依賴:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt</artifactId>
        <version>0.9.1</version>
    </dependency>
</dependencies>

2. 配置JWT工具類

創(chuàng)建一個(gè)工具類用于生成和解析JWT Token。

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.stereotype.Component;

import java.util.Date;

@Component
public class JwtTokenUtil {
    private String secretKey = "secret"; // 密鑰,實(shí)際應(yīng)用中應(yīng)保密

    public String generateAccessToken(String username) {
        return Jwts.builder()
                .setSubject(username)
                .setIssuer("YourApp")
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + 15 * 60 * 1000)) // 15分鐘后過(guò)期
                .signWith(SignatureAlgorithm.HS512, secretKey)
                .compact();
    }

    public String generateRefreshToken(String username) {
        return Jwts.builder()
                .setSubject(username)
                .setIssuer("YourApp")
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + 7 * 24 * 60 * 60 * 1000)) // 7天后過(guò)期
                .signWith(SignatureAlgorithm.HS512, secretKey)
                .compact();
    }

    public Claims getClaimsFromToken(String token) {
        return Jwts.parser()
                .setSigningKey(secretKey)
                .parseClaimsJws(token)
                .getBody();
    }
}

3. 配置Spring Security和Token驗(yàn)證過(guò)濾器

創(chuàng)建一個(gè)Security配置類和一個(gè)JWT驗(yàn)證過(guò)濾器,用于檢查和刷新Tokens。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        JwtTokenFilter jwtTokenFilter = new JwtTokenFilter(jwtTokenUtil, userDetailsService);
        
        http.csrf().disable()
            .authorizeRequests()
            .anyRequest().authenticated()
            .and()
            .addFilterBefore(jwtTokenFilter, UsernamePasswordAuthenticationFilter.class);
    }
}

在這里,JwtTokenFilter 是一個(gè)自定義的過(guò)濾器,它負(fù)責(zé)每次HTTP請(qǐng)求時(shí)檢查和刷新 access_token。這里我們使用 addFilterBefore 方法將 JwtTokenFilter 添加到 UsernamePasswordAuthenticationFilter 之前。這是因?yàn)槲覀兿M赟pring Security執(zhí)行標(biāo)準(zhǔn)身份驗(yàn)證之前處理JWT令牌的提取和驗(yàn)證。我們通過(guò)Spring的自動(dòng)裝配 (@Autowired) 功能注入了 JwtTokenUtilUserDetailsService。

4. JwtTokenFilter 實(shí)現(xiàn)

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class JwtTokenFilter extends OncePerRequestFilter {
    private JwtTokenUtil jwtTokenUtil;
    private UserDetailsService userDetailsService;

    public JwtTokenFilter(JwtTokenUtil jwtTokenUtil, UserDetailsService userDetailsService) {
        this.jwtTokenUtil = jwtTokenUtil;
        this.userDetailsService = userDetailsService;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {
        String accessToken = request.getHeader("Authorization");
        String username = null;
        Claims claims = null;

        if (accessToken != null && accessToken.startsWith("Bearer ")) {
            accessToken = accessToken.substring(7);
            try {
                claims = jwtTokenUtil.getClaimsFromToken(accessToken);
                username = claims.getSubject();
            } catch (ExpiredJwtException e) {
                // 在這里處理 access_token 過(guò)期的情況
                String refreshToken = request.getHeader("Refresh-Token");
                if (refreshToken != null && jwtTokenUtil.validateToken(refreshToken)) {
                    // 驗(yàn)證 refresh_token,如果有效則重新生成 tokens
                    username = jwtTokenUtil.getClaimsFromToken(refreshToken).getSubject();
                    String newAccessToken = jwtTokenUtil.generateAccessToken(username);
                    String newRefreshToken = jwtTokenUtil.generateRefreshToken(username);
                    
                    // 將新的 tokens 放入響應(yīng)頭
                    response.setHeader("Access-Token", newAccessToken);
                    response.setHeader("Refresh-Token", newRefreshToken);
                }
            }
        }

        if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
            UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
            if (jwtTokenUtil.validateToken(accessToken, userDetails)) {
                Authentication authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(authentication);
            }
        }
        chain.doFilter(request, response);
    }
}

過(guò)濾器首先從HTTP請(qǐng)求的 Authorization 頭中提取 access_token。如果令牌已過(guò)期,它將嘗試從 Refresh-Token 頭獲取 refresh_token。如果 refresh_token 有效,過(guò)濾器將生成新的 access_tokenrefresh_token 并將它們放入HTTP響應(yīng)頭中。如果從Token中解析出的用戶信息有效,過(guò)濾器將創(chuàng)建一個(gè)認(rèn)證對(duì)象并將其設(shè)置到 SecurityContextHolder 中,這樣,Spring Security就可以在后續(xù)處理中使用這個(gè)認(rèn)證信息。

結(jié)論

通過(guò)上述代碼,你可以在Spring Boot應(yīng)用中實(shí)現(xiàn)一個(gè)基本的無(wú)感知Token刷新機(jī)制。這只是一個(gè)基礎(chǔ)示例,實(shí)際應(yīng)用中你可能需要添加更多的錯(cuò)誤處理、日志記錄以及安全措施。此外,處理和存儲(chǔ) refresh_token 需要特別小心,因?yàn)樗哂休^長(zhǎng)的有效期并能用于獲取新的 access_token

以上就是使用SpringBoot簡(jiǎn)單實(shí)現(xiàn)無(wú)感知的刷新 Token功能的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot無(wú)感知刷新Token的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Spring中基于XML的AOP配置詳解

    Spring中基于XML的AOP配置詳解

    這篇文章主要介紹了Spring中基于XML的AOP配置,本文通過(guò)圖文實(shí)例相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-10-10
  • SpringBoot上傳文件到本服務(wù)器 目錄與jar包同級(jí)問(wèn)題

    SpringBoot上傳文件到本服務(wù)器 目錄與jar包同級(jí)問(wèn)題

    這篇文章主要介紹了SpringBoot上傳文件到本服務(wù)器 目錄與jar包同級(jí)問(wèn)題,需要的朋友可以參考下
    2018-11-11
  • 詳解Spring Cloud中Hystrix的請(qǐng)求合并

    詳解Spring Cloud中Hystrix的請(qǐng)求合并

    這篇文章主要介紹了詳解Spring Cloud中Hystrix的請(qǐng)求合并,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-05-05
  • 詳解spring多線程與定時(shí)任務(wù)

    詳解spring多線程與定時(shí)任務(wù)

    本篇文章主要介紹了spring多線程與定時(shí)任務(wù),詳細(xì)的介紹了spring多線程任務(wù)和spring定時(shí)任務(wù),有興趣的可以了解一下。
    2017-04-04
  • Springboot集成GraphicsMagick

    Springboot集成GraphicsMagick

    本文主要是教大家如何將GraphicsMagick命令行工具集成到Springboot項(xiàng)目中,便可以使用Java進(jìn)行圖片處理相關(guān)開(kāi)發(fā)。
    2021-05-05
  • Java實(shí)現(xiàn)常見(jiàn)排序算法的優(yōu)化

    Java實(shí)現(xiàn)常見(jiàn)排序算法的優(yōu)化

    今天給大家?guī)?lái)的是關(guān)于Java的相關(guān)知識(shí),文章圍繞著Java實(shí)現(xiàn)常見(jiàn)排序算法的優(yōu)化展開(kāi),文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下
    2021-01-01
  • MyBatis?在使用上的注意事項(xiàng)及其辨析(最新最全整理)

    MyBatis?在使用上的注意事項(xiàng)及其辨析(最新最全整理)

    這篇文章主要介紹了MyBatis的在使用上的注意事項(xiàng)及其辨析,本文內(nèi)容比較長(zhǎng),是小編用心給大家整理的,圖文實(shí)例代碼相結(jié)合給大家講解的非常詳細(xì),需要的朋友參考下吧
    2024-06-06
  • 如何使用Jenkins編譯并打包SpringCloud微服務(wù)目錄

    如何使用Jenkins編譯并打包SpringCloud微服務(wù)目錄

    這篇文章主要介紹了如何使用Jenkins編譯并打包SpringCloud微服務(wù)目錄,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-11-11
  • Spring使用注解更簡(jiǎn)單的讀取和存儲(chǔ)對(duì)象的方法

    Spring使用注解更簡(jiǎn)單的讀取和存儲(chǔ)對(duì)象的方法

    這篇文章主要介紹了Spring使用注解更簡(jiǎn)單的讀取和存儲(chǔ)對(duì)象的方法,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2023-07-07
  • Spring中@ConfigurationProperties的用法解析

    Spring中@ConfigurationProperties的用法解析

    這篇文章主要介紹了Spring中@ConfigurationProperties的用法解析,傳統(tǒng)的Spring一般都是基本xml配置的,后來(lái)spring3.0新增了許多java config的注解,特別是spring boot,基本都是清一色的java config,需要的朋友可以參考下
    2023-11-11

最新評(píng)論