国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

首頁 > Java > java教程 > 正文

Spring Boot Security:為特定URL模式定制JWT認(rèn)證過濾器

心靈之曲
發(fā)布: 2025-07-08 19:34:12
原創(chuàng)
920人瀏覽過

spring boot security:為特定url模式定制jwt認(rèn)證過濾器

針對(duì)Spring Boot Security中JWT過濾器默認(rèn)應(yīng)用于所有URL的問題,本文詳細(xì)闡述如何通過擴(kuò)展AbstractAuthenticationProcessingFilter并結(jié)合RequestMatcher,實(shí)現(xiàn)JWT過濾器僅對(duì) /api/** 等指定URL模式生效,從而提供更精細(xì)化的安全控制。通過此方法,開發(fā)者可以精確地控制哪些請(qǐng)求需要JWT認(rèn)證,避免不必要的性能開銷和邏輯復(fù)雜性。

在Spring Boot應(yīng)用程序中集成JWT(JSON Web Token)進(jìn)行認(rèn)證時(shí),一個(gè)常見的需求是只對(duì)特定URL模式的請(qǐng)求應(yīng)用JWT過濾器,而不是所有請(qǐng)求。默認(rèn)情況下,如果直接使用http.addFilterBefore(customJwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class),該自定義過濾器可能會(huì)在所有請(qǐng)求進(jìn)入U(xiǎn)sernamePasswordAuthenticationFilter之前被執(zhí)行,這在某些場(chǎng)景下可能不是最優(yōu)解,例如,對(duì)于公開的API或靜態(tài)資源,我們不希望它們經(jīng)過JWT認(rèn)證邏輯。

為了實(shí)現(xiàn)對(duì)特定URL模式的精確過濾,Spring Security提供了AbstractAuthenticationProcessingFilter抽象類和RequestMatcher接口,它們是解決此類問題的關(guān)鍵。

核心概念解析

  1. AbstractAuthenticationProcessingFilter: 這是Spring Security中用于處理特定認(rèn)證請(qǐng)求的抽象基類。它在內(nèi)部持有一個(gè)RequestMatcher實(shí)例,只有當(dāng)請(qǐng)求與該RequestMatcher匹配時(shí),過濾器才會(huì)嘗試進(jìn)行認(rèn)證處理(即調(diào)用attemptAuthentication方法)。這使得我們可以將認(rèn)證邏輯與請(qǐng)求路徑解耦,實(shí)現(xiàn)按需認(rèn)證。

  2. RequestMatcher: 這是一個(gè)核心接口,定義了如何判斷一個(gè)HttpServletRequest是否匹配某種規(guī)則。Spring Security提供了多種內(nèi)置實(shí)現(xiàn),例如:

    • AntPathRequestMatcher: 基于Ant風(fēng)格路徑模式(如/api/**, /users/*)進(jìn)行匹配。
    • RegexRequestMatcher: 基于正則表達(dá)式進(jìn)行匹配。
    • OrRequestMatcher: 將多個(gè)RequestMatcher通過邏輯或(OR)組合。
    • AndRequestMatcher: 將多個(gè)RequestMatcher通過邏輯與(AND)組合。 通過靈活運(yùn)用這些匹配器,我們可以構(gòu)建復(fù)雜的URL匹配邏輯。

實(shí)現(xiàn)步驟

1. 創(chuàng)建定制JWT認(rèn)證過濾器

首先,我們需要修改原有的CustomJwtAuthenticationFilter,使其繼承自AbstractAuthenticationProcessingFilter,并在構(gòu)造函數(shù)中接收一個(gè)RequestMatcher。

import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.RequestMatcher;

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

public class CustomJwtAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    // 構(gòu)造函數(shù),接收一個(gè)RequestMatcher,該匹配器定義了哪些請(qǐng)求需要此過濾器處理
    public CustomJwtAuthenticationFilter(RequestMatcher requiresAuthenticationRequestMatcher) {
        super(requiresAuthenticationRequestMatcher);
    }

    // 實(shí)際的認(rèn)證邏輯
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
            throws AuthenticationException, IOException, ServletException {
        // 從請(qǐng)求中提取JWT令牌的邏輯
        String token = extractJwtFromRequest(request);

        if (token == null) {
            // 如果沒有令牌,則拋出認(rèn)證異常,由AuthenticationEntryPoint處理
            throw new BadCredentialsException("No JWT token found in request.");
        }

        // 假設(shè)JwtAuthenticationToken是一個(gè)自定義的Authentication實(shí)現(xiàn),
        // 包含了JWT令牌信息,等待AuthenticationManager處理
        JwtAuthenticationToken authenticationToken = new JwtAuthenticationToken(token);

        // 將令牌提交給AuthenticationManager進(jìn)行認(rèn)證
        // AuthenticationManager會(huì)找到對(duì)應(yīng)的AuthenticationProvider來驗(yàn)證令牌
        return this.getAuthenticationManager().authenticate(authenticationToken);
    }

    // 輔助方法:從請(qǐng)求中提取JWT令牌
    private String extractJwtFromRequest(HttpServletRequest request) {
        // 示例:從Authorization頭中提取Bearer Token
        String bearerToken = request.getHeader("Authorization");
        if (bearerToken != null && bearerToken.startsWith("Bearer ")) {
            return bearerToken.substring(7); // 移除"Bearer "前綴
        }
        return null;
    }

    // 可以選擇性地覆蓋successfulAuthentication和unsuccessfulAuthentication方法
    // 來處理認(rèn)證成功或失敗后的邏輯,例如設(shè)置安全上下文或記錄日志。
}
登錄后復(fù)制

注意:JwtAuthenticationToken 和處理JWT令牌的AuthenticationProvider需要您自行實(shí)現(xiàn)。這里主要關(guān)注過濾器的結(jié)構(gòu)。

2. 定義請(qǐng)求匹配器

為了讓JWT過濾器僅作用于/api/**路徑,我們可以使用AntPathRequestMatcher。

import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;

// ...
// 在您的Security配置類中或單獨(dú)定義
RequestMatcher apiPathsMatcher = new AntPathRequestMatcher("/api/**");
登錄后復(fù)制

3. 集成到Spring Security配置

最后,在您的Spring Security配置類(通常是繼承WebSecurityConfigurerAdapter的類)中,將這個(gè)定制的JWT過濾器添加到過濾器鏈中。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.AuthenticationEntryPoint; // 假設(shè)您有自定義的認(rèn)證入口點(diǎn)

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private final UserDetailsService userDetailsService; // 假設(shè)您有UserDetailsService
    private final AuthenticationEntryPoint jwtAuthenticationEntryPoint; // 假設(shè)您有JWT認(rèn)證入口點(diǎn)

    public SecurityConfig(UserDetailsService userDetailsService, AuthenticationEntryPoint jwtAuthenticationEntryPoint) {
        this.userDetailsService = userDetailsService;
        this.jwtAuthenticationEntryPoint = jwtAuthenticationEntryPoint;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 配置您的AuthenticationManager,例如使用UserDetailsService和密碼編碼器
        auth.userDetailsService(userDetailsService);
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        // 暴露AuthenticationManager為Bean,供CustomJwtAuthenticationFilter使用
        return super.authenticationManagerBean();
    }

    // 定義CustomJwtAuthenticationFilter為Bean
    @Bean
    public CustomJwtAuthenticationFilter customJwtAuthenticationFilter() throws Exception {
        // 創(chuàng)建一個(gè)匹配器,指定只有/api/**路徑的請(qǐng)求才會(huì)被此JWT過濾器處理
        AntPathRequestMatcher apiMatcher = new AntPathRequestMatcher("/api/**");
        CustomJwtAuthenticationFilter filter = new CustomJwtAuthenticationFilter(apiMatcher);
        // 必須設(shè)置AuthenticationManager,因?yàn)锳bstractAuthenticationProcessingFilter需要它來執(zhí)行認(rèn)證
        filter.setAuthenticationManager(authenticationManagerBean());
        // 可以選擇性設(shè)置認(rèn)證成功/失敗處理器
        // filter.setAuthenticationSuccessHandler(...)
        // filter.setAuthenticationFailureHandler(...)
        return filter;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable() // 禁用CSRF,因?yàn)镴WT通常是無狀態(tài)的
            .authorizeRequests()
                // 確保/api/**路徑需要認(rèn)證。當(dāng)請(qǐng)求到達(dá)這些路徑時(shí),如果尚未認(rèn)證,
                // customJwtAuthenticationFilter會(huì)嘗試處理
                .antMatchers("/api/**").authenticated()
                // 其他路徑可以設(shè)置為permitAll()或根據(jù)需求配置
                .antMatchers("/users", "/login", "/").permitAll()
                .anyRequest().authenticated() // 任何其他未匹配的請(qǐng)求也需要認(rèn)證
            .and()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) // JWT是無狀態(tài)的
            .and()
            .exceptionHandling()
                .authenticationEntryPoint(jwtAuthenticationEntryPoint) // 未認(rèn)證或認(rèn)證失敗的入口點(diǎn)
                .accessDeniedPage("/403") // 訪問被拒絕的頁面
            .and()
            // 將自定義的JWT過濾器添加到UsernamePasswordAuthenticationFilter之前
            // CustomJwtAuthenticationFilter現(xiàn)在只處理/api/**路徑
            .addFilterBefore(customJwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
    }
}
登錄后復(fù)制

在上述配置中,antMatchers("/api/**").authenticated() 確保了所有/api/**路徑的請(qǐng)求都需要認(rèn)證。當(dāng)請(qǐng)求匹配/api/**時(shí),customJwtAuthenticationFilter會(huì)嘗試提取并驗(yàn)證JWT令牌。如果令牌有效,請(qǐng)求將繼續(xù)處理;否則,jwtAuthenticationEntryPoint將介入處理認(rèn)證失敗。對(duì)于其他未匹配/api/**的路徑,customJwtAuthenticationFilter根本不會(huì)被觸發(fā),從而實(shí)現(xiàn)了精確的過濾。

注意事項(xiàng)

  1. AuthenticationManager的注入與設(shè)置:AbstractAuthenticationProcessingFilter需要一個(gè)AuthenticationManager來委托實(shí)際的認(rèn)證過程。因此,您必須通過@Bean注解將authenticationManagerBean()暴露為一個(gè)Bean,并在創(chuàng)建CustomJwtAuthenticationFilter實(shí)例時(shí)將其設(shè)置進(jìn)去。
  2. 過濾器鏈順序:addFilterBefore(customJwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)的順序至關(guān)重要。它確保了在Spring Security默認(rèn)的表單登錄過濾器之前,我們的JWT過濾器有機(jī)會(huì)處理請(qǐng)求。
  3. RequestMatcher的靈活性:除了AntPathRequestMatcher,您還可以根據(jù)需要使用OrRequestMatcher、AndRequestMatcher等組合多個(gè)匹配規(guī)則,以實(shí)現(xiàn)更復(fù)雜的URL過濾邏輯。例如,如果您想過濾/api/v1/**和/admin/**,可以使用new OrRequestMatcher(new AntPathRequestMatcher("/api/v1/**"), new AntPathRequestMatcher("/admin/**"))。
  4. 認(rèn)證入口點(diǎn)(AuthenticationEntryPoint):當(dāng)CustomJwtAuthenticationFilter嘗試認(rèn)證失敗時(shí)(例如,沒有提供令牌或令牌無效),它會(huì)拋出AuthenticationException。此時(shí),authenticationEntryPoint會(huì)負(fù)責(zé)處理這個(gè)異常,通常是返回一個(gè)401 Unauthorized響應(yīng)。確保您的jwtAuthenticationEntryPoint能夠正確處理這種情況。
  5. 無狀態(tài)會(huì)話:JWT通常用于無狀態(tài)認(rèn)證,因此將sessionCreationPolicy設(shè)置為STATELESS是最佳實(shí)踐,這會(huì)禁用Spring Security的會(huì)話管理,并確保每次請(qǐng)求都攜帶JWT進(jìn)行認(rèn)證。
  6. 錯(cuò)誤處理:在attemptAuthentication方法中,如果無法提取或解析JWT,應(yīng)拋出適當(dāng)?shù)腁uthenticationException,讓Spring Security的異常處理機(jī)制(通過AuthenticationEntryPoint)來統(tǒng)一處理。

總結(jié)

通過繼承AbstractAuthenticationProcessingFilter并利用RequestMatcher,我們可以為Spring Boot Security中的JWT認(rèn)證過濾器實(shí)現(xiàn)精準(zhǔn)的URL模式匹配。這種方法不僅提高了應(yīng)用程序的安全性,因?yàn)樗辉诒匾獣r(shí)才執(zhí)行認(rèn)證邏輯,同時(shí)也優(yōu)化了性能,避免了不必要的處理開銷。掌握這種技術(shù),能夠幫助開發(fā)者構(gòu)建更加健壯和高效的Spring Security認(rèn)證體系。

以上就是Spring Boot Security:為特定URL模式定制JWT認(rèn)證過濾器的詳細(xì)內(nèi)容,更多請(qǐng)關(guān)注php中文網(wǎng)其它相關(guān)文章!

最佳 Windows 性能的頂級(jí)免費(fèi)優(yōu)化軟件
最佳 Windows 性能的頂級(jí)免費(fèi)優(yōu)化軟件

每個(gè)人都需要一臺(tái)速度更快、更穩(wěn)定的 PC。隨著時(shí)間的推移,垃圾文件、舊注冊(cè)表數(shù)據(jù)和不必要的后臺(tái)進(jìn)程會(huì)占用資源并降低性能。幸運(yùn)的是,許多工具可以讓 Windows 保持平穩(wěn)運(yùn)行。

下載
本文內(nèi)容由網(wǎng)友自發(fā)貢獻(xiàn),版權(quán)歸原作者所有,本站不承擔(dān)相應(yīng)法律責(zé)任。如您發(fā)現(xiàn)有涉嫌抄襲侵權(quán)的內(nèi)容,請(qǐng)聯(lián)系admin@php.cn
最新問題
開源免費(fèi)商場(chǎng)系統(tǒng)廣告
最新下載
更多>
網(wǎng)站特效
網(wǎng)站源碼
網(wǎng)站素材
前端模板
關(guān)于我們 免責(zé)申明 意見反饋 講師合作 廣告合作 最新更新
php中文網(wǎng):公益在線php培訓(xùn),幫助PHP學(xué)習(xí)者快速成長(zhǎng)!
關(guān)注服務(wù)號(hào) 技術(shù)交流群
PHP中文網(wǎng)訂閱號(hào)
每天精選資源文章推送
PHP中文網(wǎng)APP
隨時(shí)隨地碎片化學(xué)習(xí)
PHP中文網(wǎng)抖音號(hào)
發(fā)現(xiàn)有趣的

Copyright 2014-2025 http://m.miracleart.cn/ All Rights Reserved | php.cn | 湘ICP備2023035733號(hào)