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

首頁 Java java教程 Spring 授權(quán)服務(wù)器 spring security 具有自定義用戶詳細(xì)信息服務(wù),用于靈活的數(shù)據(jù)驅(qū)動(dòng)身份驗(yàn)證

Spring 授權(quán)服務(wù)器 spring security 具有自定義用戶詳細(xì)信息服務(wù),用于靈活的數(shù)據(jù)驅(qū)動(dòng)身份驗(yàn)證

Jan 23, 2025 pm 12:07 PM

Spring授權(quán)服務(wù)器

Spring 授權(quán)服務(wù)器是一個(gè)旨在實(shí)現(xiàn) OAuth 2.1 和 OpenID Connect 1.0 規(guī)范以及其他相關(guān)標(biāo)準(zhǔn)的框架。它基于 Spring Security 構(gòu)建,為創(chuàng)建符合 OpenID Connect 1.0 和 OAuth2 授權(quán)服務(wù)器解決方案的身份提供者提供了安全、輕量級(jí)和可定制的基礎(chǔ)。

功能列表

什么是 Spring Security 以及它是如何工作的?

簡(jiǎn)短回答
Spring Security 是一個(gè)功能強(qiáng)大且高度可定制的身份驗(yàn)證和訪問控制框架。它是保護(hù)基于 Spring 的應(yīng)用程序的事實(shí)標(biāo)準(zhǔn)。

本質(zhì)上,Spring Security 本質(zhì)上是 servlet 過濾器的集合,旨在通過強(qiáng)大的身份驗(yàn)證和授權(quán)功能來增強(qiáng)您的 Web 應(yīng)用程序。

Spring Security 還與 Spring Web MVC 或 Spring Boot 等框架很好地配合,支持 OAuth2 和 SAML 等標(biāo)準(zhǔn)。它自動(dòng)生成登錄和注銷接口,并保護(hù)您的應(yīng)用程序免受 CSRF 等常見安全漏洞的影響。

嗯,這不是很有幫助,不是嗎?

讓我們深入研究網(wǎng)絡(luò)安全,以掌握其安全工作流程的要點(diǎn)。

要成為Spring Security專家,首先要掌握這三個(gè)核心概念:

  • 身份驗(yàn)證
  • 授權(quán)
  • Servlet 過濾器

注意 - 不要繞過此部分;它為所有 Spring Security 功能奠定了基礎(chǔ)。

驗(yàn)證

您需要在線訪問您的銀行賬戶以查看余額或進(jìn)行交易。通常這是使用用戶名和密碼完成的

用戶:“我是 John Doe。我的用戶名是:johndoe1985?!?br> 銀行系統(tǒng):“請(qǐng)驗(yàn)證您的身份。您的密碼是多少?”
用戶:“我的密碼是:secureB@nk2023?!?br> 銀行系統(tǒng):“歡迎,John Doe。這是您的帳戶概覽?!?/p>

授權(quán)

對(duì)于基本應(yīng)用程序,僅進(jìn)行身份驗(yàn)證就足夠了:用戶登錄后,他們將被授予訪問應(yīng)用程序所有區(qū)域的權(quán)限。

但是,在大多數(shù)應(yīng)用程序中,都有權(quán)限或角色在發(fā)揮作用。

用戶:“讓我來玩一下該交易......”
銀行系統(tǒng):“等一下,我需要先檢查您的權(quán)限……是的,John Doe 先生,您的權(quán)限級(jí)別正確。盡情享受吧?!?br> 用戶:“我轉(zhuǎn)1M哈哈哈……?開玩笑開玩笑”

小服務(wù)程序過濾器

現(xiàn)在,讓我們探索 Servlet 過濾器。它們與身份驗(yàn)證和授權(quán)有何關(guān)系?

為什么使用 Servlet 過濾器?
每個(gè) Spring Web 應(yīng)用程序都圍繞一個(gè) servlet 展開:值得信賴的 DispatcherServlet。它的主要作用是將傳入的 HTTP 請(qǐng)求(例如來自瀏覽器的請(qǐng)求)路由到適當(dāng)?shù)?@Controller 或 @RestController 進(jìn)行處理。

事情是這樣的:DispatcherServlet 本身沒有任何內(nèi)置的安全功能,并且您可能不想直接在 @Controller 中處理原始 HTTP Basic Auth 標(biāo)頭。理想情況下,在請(qǐng)求到達(dá)您的 @Controllers

之前就應(yīng)該處理身份驗(yàn)證和授權(quán)

幸運(yùn)的是,在 Java Web 環(huán)境中,您可以通過在 servlet 之前放置過濾器來實(shí)現(xiàn)這一點(diǎn)。這意味著您可以考慮創(chuàng)建一個(gè) SecurityFilter 并將其設(shè)置在 Tomcat(servlet 容器/應(yīng)用程序服務(wù)器)中,以在每個(gè)傳入的 HTTP 請(qǐng)求到達(dá)您的 servlet 之前攔截和處理它。

Security context

SecurityFilter 大約有 4 個(gè)任務(wù)

  1. 首先,過濾器需要從請(qǐng)求中提取用戶名/密碼。它可以通過基本身份驗(yàn)證 HTTP 標(biāo)頭、表單字段或 cookie 等實(shí)現(xiàn)。
  2. 然后過濾器需要根據(jù)數(shù)據(jù)庫等內(nèi)容驗(yàn)證用戶名/密碼組合。
  3. 過濾器需要在身份驗(yàn)證成功后檢查用戶是否有權(quán)訪問所請(qǐng)求的 URI。
  4. 如果請(qǐng)求通過了所有這些檢查,那么過濾器就可以 讓請(qǐng)求傳遞到您的 DispatcherServlet,即您的 @Controllers。

過濾器鏈

在實(shí)踐中,我們會(huì)將一個(gè)過濾器分解為多個(gè)過濾器,然后您可以將它們鏈接在一起。

以下是傳入 HTTP 請(qǐng)求的傳輸方式:

  1. 首先,它通過 LoginMethodFilter...
  2. 接下來,它會(huì)通過 AuthenticationFilter...
  3. 然后,它移動(dòng)到 AuthorizationFilter...
  4. 最后,它到達(dá)您的 servlet。

此設(shè)置稱為 FilterChain。

通過使用過濾器(或一系列過濾器),您可以有效地管理應(yīng)用程序中的所有身份驗(yàn)證和授權(quán)挑戰(zhàn),而無需更改 @RestControllers 或 @Controllers 的核心實(shí)現(xiàn)。

Spring 的 DefaultSecurityFilterChain

假設(shè)您已經(jīng)正確配置了 Spring Security 并啟動(dòng)了您的 Web 應(yīng)用程序。您會(huì)注意到一條日志消息,如下所示:

2020-02-25 10:24:27.875  INFO 11116 --- [           main] o.s.s.web.DefaultSecurityFilterChain     : Creating filter chain: any request, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@46320c9a, org.springframework.security.web.context.SecurityContextPersistenceFilter@4d98e41b, org.springframework.security.web.header.HeaderWriterFilter@52bd9a27, org.springframework.security.web.csrf.CsrfFilter@51c65a43, org.springframework.security.web.authentication.logout.LogoutFilter@124d26ba, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@61e86192, org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@10980560, org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter@32256e68, org.springframework.security.web.authentication.www.BasicAuthenticationFilter@52d0f583, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@5696c927, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@5f025000, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@5e7abaf7, org.springframework.security.web.session.SessionManagementFilter@681c0ae6, org.springframework.security.web.access.ExceptionTranslationFilter@15639d09, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@4f7be6c8]|

擴(kuò)展這一行表明 Spring Security 不僅僅添加一個(gè)過濾器,它還設(shè)置了一個(gè)包含 15 個(gè)(?。┎煌^濾器的完整過濾器鏈。

當(dāng) HTTP 請(qǐng)求到達(dá)時(shí),它會(huì)依次通過這 15 個(gè)過濾器中的每一個(gè),然后最終到達(dá)您的 @RestControllers。這些過濾器的順序至關(guān)重要,因?yàn)檎?qǐng)求是從鏈的頂部到底部處理的。

security chain

分析 Spring 的 FilterChain

深入研究鏈中每個(gè)過濾器的細(xì)節(jié)會(huì)讓我們走得太遠(yuǎn),但這里是一些關(guān)鍵過濾器的解釋。為了更深入地了解其他內(nèi)容,您可以探索 Spring Security 的源代碼。

  1. BasicAuthenticationFilter:嘗試在請(qǐng)求中查找基本身份驗(yàn)證 HTTP 標(biāo)頭,如果找到,則嘗試使用標(biāo)頭的用戶名和密碼對(duì)用戶進(jìn)行身份驗(yàn)證。
  2. UsernamePasswordAuthenticationFilter:嘗試查找用戶名/密碼請(qǐng)求參數(shù)/POST 正文,如果找到,則嘗試使用這些值對(duì)用戶進(jìn)行身份驗(yàn)證。
  3. DefaultLoginPageGenerateFilter:如果您沒有明確禁用該功能,則會(huì)為您生成登錄頁面。這個(gè)過濾器就是您在啟用 Spring Security 時(shí)獲得默認(rèn)登錄頁面的原因。
  4. DefaultLogoutPageGenerateFilter:如果您沒有明確禁用該功能,則會(huì)為您生成一個(gè)注銷頁面。
  5. FilterSecurityInterceptor:是否經(jīng)過您的授權(quán)。

開玩笑

問題 - 為什么 HTTP 請(qǐng)求會(huì)被 Spring Security 過濾器破壞?
回答 - 因?yàn)槊看嗡噲D靠近時(shí),過濾器都會(huì)說:“等一下!讓我先檢查一下你!” ?

是的,休息......哇,等等......這一次的安全討論太多了!

設(shè)置 Spring 授權(quán)服務(wù)器

開始使用 Spring 授權(quán)服務(wù)器的最簡(jiǎn)單方法是創(chuàng)建基于 Spring Boot 的應(yīng)用程序。您可以使用start.spring.io生成一個(gè)基本項(xiàng)目。

唯一需要的依賴是實(shí)現(xiàn)(“org.springframework.boot:spring-boot-starter-oauth2-authorization-server”)

我們將添加另外兩個(gè)來執(zhí)行更多操作

2020-02-25 10:24:27.875  INFO 11116 --- [           main] o.s.s.web.DefaultSecurityFilterChain     : Creating filter chain: any request, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@46320c9a, org.springframework.security.web.context.SecurityContextPersistenceFilter@4d98e41b, org.springframework.security.web.header.HeaderWriterFilter@52bd9a27, org.springframework.security.web.csrf.CsrfFilter@51c65a43, org.springframework.security.web.authentication.logout.LogoutFilter@124d26ba, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@61e86192, org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@10980560, org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter@32256e68, org.springframework.security.web.authentication.www.BasicAuthenticationFilter@52d0f583, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@5696c927, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@5f025000, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@5e7abaf7, org.springframework.security.web.session.SessionManagementFilter@681c0ae6, org.springframework.security.web.access.ExceptionTranslationFilter@15639d09, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@4f7be6c8]|

如何配置 Spring Security

使用最新的 Spring Security 和/或 Spring Boot 版本,配置 Spring Security 的方法是使用一個(gè)類: 使用 @EnableWebSecurity 注解。

dependencies {
    implementation("org.springframework.boot:spring-boot-starter-oauth2-authorization-server")
    implementation("org.springframework.boot:spring-boot-starter-webflux")
    implementation("org.springframework.boot:spring-boot-starter-validation")
}

(1):協(xié)議端點(diǎn)的 Spring Security 過濾器鏈。
(2) :用于身份驗(yàn)證的 Spring Security 過濾器鏈。
(3) : com.nimbusds.jose.jwk.source.JWKSource 的實(shí)例,用于簽署訪問令牌。
(4) : 用于解碼簽名訪問令牌的 JwtDecoder 實(shí)例。
(5) : AuthorizationServerSettings 實(shí)例,用于配置 Spring Authorization Server。

讓我們配置 CORS 以允許某些 URL 訪問我們的應(yīng)用程序

2020-02-25 10:24:27.875  INFO 11116 --- [           main] o.s.s.web.DefaultSecurityFilterChain     : Creating filter chain: any request, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@46320c9a, org.springframework.security.web.context.SecurityContextPersistenceFilter@4d98e41b, org.springframework.security.web.header.HeaderWriterFilter@52bd9a27, org.springframework.security.web.csrf.CsrfFilter@51c65a43, org.springframework.security.web.authentication.logout.LogoutFilter@124d26ba, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@61e86192, org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@10980560, org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter@32256e68, org.springframework.security.web.authentication.www.BasicAuthenticationFilter@52d0f583, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@5696c927, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@5f025000, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@5e7abaf7, org.springframework.security.web.session.SessionManagementFilter@681c0ae6, org.springframework.security.web.access.ExceptionTranslationFilter@15639d09, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@4f7be6c8]|

Cors配置
該類用于定義CORS規(guī)則。在這種情況下:

  • addAllowedOrigin("http://localhost:3000/"):允許來自 http://localhost:3000 的請(qǐng)求。當(dāng)您的前端在不同端口上運(yùn)行時(shí),這對(duì)于本地開發(fā)非常有用。在生產(chǎn)中,將其替換為您的實(shí)際域。
  • addAllowedMethod("*"):允許所有 HTTP 方法(例如 GET、POST、PUT、DELETE 等)。
  • addAllowedHeader("*"):允許請(qǐng)求中的所有 HTTP 標(biāo)頭。

UrlBasedCorsConfigurationSource

  • 將 URL 模式(如 /**)映射到特定 CORS 配置的類。
  • registerCorsConfiguration("/", configuration):將定義的 CORS 規(guī)則(配置)應(yīng)用于應(yīng)用程序中的所有端點(diǎn) (/)。

哇,配置太多了!但這就是 Spring 框架的魔力——它處理幕后的所有繁重工作。

是時(shí)候配置客戶端了

dependencies {
    implementation("org.springframework.boot:spring-boot-starter-oauth2-authorization-server")
    implementation("org.springframework.boot:spring-boot-starter-webflux")
    implementation("org.springframework.boot:spring-boot-starter-validation")
}

上面我們做了一些事情

  1. clientId:允許訪問的唯一標(biāo)識(shí)符
  2. clientAuthenticationMethod :定義身份驗(yàn)證方法
  3. redirectUris 僅允許定義的 URL
  4. authorizationGrantTypes 授權(quán)代碼

用戶詳情服務(wù)

UserDetailsS??ervice 由 DaoAuthenticationProvider 用于檢索 用戶名密碼以及其他用于使用用戶名和密碼進(jìn)行身份驗(yàn)證的屬性。 Spring Security 提供了 UserDetailsS??ervice 的內(nèi)存、JDBC 和緩存實(shí)現(xiàn)。

您可以通過將自定義 UserDetailsS??ervice 公開為 bean 來定義自定義身份驗(yàn)證。

內(nèi)存中用戶詳細(xì)信息管理器

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    private static final String[] ALLOW_LIST = {"/oauth2/token", "/userinfo"};
    //This is primarily configured to handle OAuth2 and OpenID Connect specific endpoints. It sets up the security for the authorization server, handling token endpoints, client authentication, etc.
    @Bean (1)
    @Order(1)
    public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
        OAuth2AuthorizationServerConfigurer authorizationServerConfigurer = OAuth2AuthorizationServerConfigurer.authorizationServer();
        http
                .cors(Customizer.withDefaults())
                .authorizeHttpRequests(authz -> authz
                        .requestMatchers(ALLOW_LIST).permitAll()
                        .requestMatchers("/**", "/oauth2/jwks/").hasAuthority("SCOPE_keys.write")
                        .anyRequest()
                        .authenticated())
                .securityMatchers(matchers ->
                        matchers.requestMatchers(antMatcher("/oauth2/**"), authorizationServerConfigurer.getEndpointsMatcher()))
                .with(authorizationServerConfigurer, (authorizationServer) ->
                        authorizationServer
                        .oidc(Customizer.withDefaults()))    // Enable OpenID Connect 1.0

                // Redirect to the login page when not authenticated from the
                // authorization endpoint
                .exceptionHandling((exceptions) -> exceptions
                        .defaultAuthenticationEntryPointFor(
                                new LoginUrlAuthenticationEntryPoint("/login"),
                                new MediaTypeRequestMatcher(MediaType.TEXT_HTML)
                        ))
                // Accept access tokens for User Info and/or Client Registration
                .oauth2ResourceServer((oauth2) -> oauth2.jwt(Customizer.withDefaults()));
        return http.build();
    }

    // This configuration is set up for general application security, handling standard web security features like form login for paths not specifically managed by the OAuth2 configuration.
    @Bean (2)
    @Order(2)
    public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http)
            throws Exception {
        http
                .authorizeHttpRequests((authorize) -> authorize
                        .requestMatchers("/login", "/error", "/main.css")
                        .permitAll()
                        .anyRequest()
                        .authenticated()
                )
                // Form login handles the redirect to the login page from the
                // authorization server filter chain
                .formLogin((login) -> login.loginPage("/login"));

        return http.build();
    }

    @Bean (3)
    public JWKSource<SecurityContext> jwkSource() {
        KeyPair keyPair = generateRsaKey();
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        RSAKey rsaKey = new RSAKey.Builder(publicKey)
                .privateKey(privateKey)
                .keyID(UUID.randomUUID().toString())
                .build();
        JWKSet jwkSet = new JWKSet(rsaKey);
        return new ImmutableJWKSet<>(jwkSet);
    }

    private static KeyPair generateRsaKey() {
        KeyPair keyPair;
        try {
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
            keyPairGenerator.initialize(2048);
            keyPair = keyPairGenerator.generateKeyPair();
        } catch (Exception ex) {
            throw new IllegalStateException(ex);
        }
        return keyPair;
    }


    @Bean (4)
    public JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {
        return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);
    }

    @Bean (5)
    public AuthorizationServerSettings authorizationServerSettings() {
        return AuthorizationServerSettings
                .builder()
                .build();
    }

}

一旦我們啟動(dòng)應(yīng)用程序,我們的 OIDC 和 OAuth2 設(shè)置與 Spring 授權(quán)服務(wù)器應(yīng)該可以正常運(yùn)行。但是,您會(huì)注意到我們使用了 InMemoryUserDetailsManager,它非常適合演示或原型設(shè)計(jì)。但對(duì)于生產(chǎn)環(huán)境,這是不可取的,因?yàn)閼?yīng)用程序重新啟動(dòng)后所有數(shù)據(jù)都會(huì)消失。

Spring Security 中的 JdbcUserDetailsManager

JdbcUserDetailsManager 是 Spring Security 中的一項(xiàng)功能,它使用 JDBC 通過連接到關(guān)系數(shù)據(jù)庫來處理用戶憑據(jù)和角色。當(dāng)您的應(yīng)用程序可以使用 Spring Security 期望的用戶表的標(biāo)準(zhǔn)架構(gòu)時(shí),這是理想的選擇。

可從 Spring security org/springframework/security/core/userdetails/jdbc/users.ddl
獲得的架構(gòu)

@Configuration
public class CorsConfig {

    @Bean
    public UrlBasedCorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.addAllowedOrigin("http://localhost:3000/"); // Change to specific domains in production
        configuration.addAllowedMethod("*");
        configuration.addAllowedHeader("*");
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
}

從 InMemoryUserDetailsManager 轉(zhuǎn)換到 JdbcUserDetailsManager 所需的唯一調(diào)整

2020-02-25 10:24:27.875  INFO 11116 --- [           main] o.s.s.web.DefaultSecurityFilterChain     : Creating filter chain: any request, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@46320c9a, org.springframework.security.web.context.SecurityContextPersistenceFilter@4d98e41b, org.springframework.security.web.header.HeaderWriterFilter@52bd9a27, org.springframework.security.web.csrf.CsrfFilter@51c65a43, org.springframework.security.web.authentication.logout.LogoutFilter@124d26ba, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@61e86192, org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@10980560, org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter@32256e68, org.springframework.security.web.authentication.www.BasicAuthenticationFilter@52d0f583, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@5696c927, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@5f025000, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@5e7abaf7, org.springframework.security.web.session.SessionManagementFilter@681c0ae6, org.springframework.security.web.access.ExceptionTranslationFilter@15639d09, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@4f7be6c8]|

此配置對(duì)于堅(jiān)持 Spring Security 標(biāo)準(zhǔn)表模式的應(yīng)用程序有效。但是,如果您需要自定義(例如使用電子郵件而不是用戶名進(jìn)行登錄),則實(shí)現(xiàn)自定義 UserDetailsS??ervice 可提供必要的適應(yīng)性。

帶有客戶實(shí)體的自定義 UserDetailsS??ervice

讓我們向提供程序添加自定義 CustomUserDetailsS??ervice。在 AuthenticationProvider 中使用 setUserDetailsS??ervice
設(shè)置自定義服務(wù)

dependencies {
    implementation("org.springframework.boot:spring-boot-starter-oauth2-authorization-server")
    implementation("org.springframework.boot:spring-boot-starter-webflux")
    implementation("org.springframework.boot:spring-boot-starter-validation")
}

定制服務(wù)

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    private static final String[] ALLOW_LIST = {"/oauth2/token", "/userinfo"};
    //This is primarily configured to handle OAuth2 and OpenID Connect specific endpoints. It sets up the security for the authorization server, handling token endpoints, client authentication, etc.
    @Bean (1)
    @Order(1)
    public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
        OAuth2AuthorizationServerConfigurer authorizationServerConfigurer = OAuth2AuthorizationServerConfigurer.authorizationServer();
        http
                .cors(Customizer.withDefaults())
                .authorizeHttpRequests(authz -> authz
                        .requestMatchers(ALLOW_LIST).permitAll()
                        .requestMatchers("/**", "/oauth2/jwks/").hasAuthority("SCOPE_keys.write")
                        .anyRequest()
                        .authenticated())
                .securityMatchers(matchers ->
                        matchers.requestMatchers(antMatcher("/oauth2/**"), authorizationServerConfigurer.getEndpointsMatcher()))
                .with(authorizationServerConfigurer, (authorizationServer) ->
                        authorizationServer
                        .oidc(Customizer.withDefaults()))    // Enable OpenID Connect 1.0

                // Redirect to the login page when not authenticated from the
                // authorization endpoint
                .exceptionHandling((exceptions) -> exceptions
                        .defaultAuthenticationEntryPointFor(
                                new LoginUrlAuthenticationEntryPoint("/login"),
                                new MediaTypeRequestMatcher(MediaType.TEXT_HTML)
                        ))
                // Accept access tokens for User Info and/or Client Registration
                .oauth2ResourceServer((oauth2) -> oauth2.jwt(Customizer.withDefaults()));
        return http.build();
    }

    // This configuration is set up for general application security, handling standard web security features like form login for paths not specifically managed by the OAuth2 configuration.
    @Bean (2)
    @Order(2)
    public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http)
            throws Exception {
        http
                .authorizeHttpRequests((authorize) -> authorize
                        .requestMatchers("/login", "/error", "/main.css")
                        .permitAll()
                        .anyRequest()
                        .authenticated()
                )
                // Form login handles the redirect to the login page from the
                // authorization server filter chain
                .formLogin((login) -> login.loginPage("/login"));

        return http.build();
    }

    @Bean (3)
    public JWKSource<SecurityContext> jwkSource() {
        KeyPair keyPair = generateRsaKey();
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        RSAKey rsaKey = new RSAKey.Builder(publicKey)
                .privateKey(privateKey)
                .keyID(UUID.randomUUID().toString())
                .build();
        JWKSet jwkSet = new JWKSet(rsaKey);
        return new ImmutableJWKSet<>(jwkSet);
    }

    private static KeyPair generateRsaKey() {
        KeyPair keyPair;
        try {
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
            keyPairGenerator.initialize(2048);
            keyPair = keyPairGenerator.generateKeyPair();
        } catch (Exception ex) {
            throw new IllegalStateException(ex);
        }
        return keyPair;
    }


    @Bean (4)
    public JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {
        return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);
    }

    @Bean (5)
    public AuthorizationServerSettings authorizationServerSettings() {
        return AuthorizationServerSettings
                .builder()
                .build();
    }

}

存儲(chǔ)庫

@Configuration
public class CorsConfig {

    @Bean
    public UrlBasedCorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.addAllowedOrigin("http://localhost:3000/"); // Change to specific domains in production
        configuration.addAllowedMethod("*");
        configuration.addAllowedHeader("*");
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
}

實(shí)體

@Configuration
public class Clients {
    @Bean
    public RegisteredClientRepository registeredClientRepository() {
        RegisteredClient oidcClient = RegisteredClient.withId(UUID.randomUUID().toString())
                .clientId("stomble")
                .clientAuthenticationMethod(ClientAuthenticationMethod.NONE)
                .authorizationGrantTypes(types -> {
                    types.add(AuthorizationGrantType.AUTHORIZATION_CODE);
                    types.add(AuthorizationGrantType.REFRESH_TOKEN);
                })
                .redirectUris(redirectUri -> {
                    redirectUri.add("http://localhost:3000");
                    redirectUri.add("https://oauth.pstmn.io/v1/callback");
                    redirectUri.add("http://localhost:3000/signin-callback");
                })
                .postLogoutRedirectUri("http://localhost:3000")
                .scopes(score -> {
                    score.add(OidcScopes.OPENID);
                    score.add(OidcScopes.PROFILE);
                    score.add(OidcScopes.EMAIL);
                })
                .clientSettings(ClientSettings.builder()
                        .requireAuthorizationConsent(false)
                        .requireProofKey(true)
                        .build())
                .build();
        return new InMemoryRegisteredClientRepository(oidcClient);
    }
}

在安全過濾器中,我們必須告訴 spring security 使用此服務(wù)

.clientAuthentication(clientAuth -> clientAuth.authenticationProvider(authenticationProvider))

@Configuration
public class UserConfig {

    @Bean
    public UserDetailsService userDetailsService(PasswordEncoder passwordEncoder) {
        UserDetails userDetailFirst = User.builder()
                .username("user1")
                .password(passwordEncoder.encode("password"))
                .roles("USER")
                .build();
        UserDetails userDetailSecond = User.builder()
                .username("user2")
                .password(passwordEncoder.encode("password"))
                .roles("USER")
                .build();
        return new InMemoryUserDetailsManager(List.of(userDetailFirst, userDetailSecond));
    }
}

@Bean
public PasswordEncoder passwordEncoder() {
   return new BCryptPasswordEncoder();
}

結(jié)論

在這里,您有兩個(gè)強(qiáng)大的選擇來處理身份驗(yàn)證:

  • JdbcUserDetailsManager:如果您的應(yīng)用程序與 Spring 的默認(rèn)架構(gòu)一致,這是一個(gè)簡(jiǎn)單的選項(xiàng)。
  • 自定義 UserDetailsS??ervice:提供管理特殊字段和角色的靈活性。

無論您選擇 JdbcUserDetailsManager 還是決定實(shí)現(xiàn)自定義 UserDetailsS??ervice,兩者都將為您的應(yīng)用程序配備可擴(kuò)展的、數(shù)據(jù)庫支持的身份驗(yàn)證系統(tǒng)。

以上是Spring 授權(quán)服務(wù)器 spring security 具有自定義用戶詳細(xì)信息服務(wù),用于靈活的數(shù)據(jù)驅(qū)動(dòng)身份驗(yàn)證的詳細(xì)內(nèi)容。更多信息請(qǐng)關(guān)注PHP中文網(wǎng)其他相關(guā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

熱AI工具

Undress AI Tool

Undress AI Tool

免費(fèi)脫衣服圖片

Undresser.AI Undress

Undresser.AI Undress

人工智能驅(qū)動(dòng)的應(yīng)用程序,用于創(chuàng)建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用于從照片中去除衣服的在線人工智能工具。

Clothoff.io

Clothoff.io

AI脫衣機(jī)

Video Face Swap

Video Face Swap

使用我們完全免費(fèi)的人工智能換臉工具輕松在任何視頻中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費(fèi)的代碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

功能強(qiáng)大的PHP集成開發(fā)環(huán)境

Dreamweaver CS6

Dreamweaver CS6

視覺化網(wǎng)頁開發(fā)工具

SublimeText3 Mac版

SublimeText3 Mac版

神級(jí)代碼編輯軟件(SublimeText3)

hashmap和hashtable之間的區(qū)別? hashmap和hashtable之間的區(qū)別? Jun 24, 2025 pm 09:41 PM

HashMap與Hashtable的區(qū)別主要體現(xiàn)在線程安全、null值支持及性能方面。1.線程安全方面,Hashtable是線程安全的,其方法大多為同步方法,而HashMap不做同步處理,非線程安全;2.null值支持上,HashMap允許一個(gè)null鍵和多個(gè)null值,Hashtable則不允許null鍵或值,否則拋出NullPointerException;3.性能方面,HashMap因無同步機(jī)制效率更高,Hashtable因每次操作加鎖性能較低,推薦使用ConcurrentHashMap替

為什么我們需要包裝紙課? 為什么我們需要包裝紙課? Jun 28, 2025 am 01:01 AM

Java使用包裝類是因?yàn)榛緮?shù)據(jù)類型無法直接參與面向?qū)ο蟛僮?,而?shí)際需求中常需對(duì)象形式;1.集合類只能存儲(chǔ)對(duì)象,如List利用自動(dòng)裝箱存儲(chǔ)數(shù)值;2.泛型不支持基本類型,必須使用包裝類作為類型參數(shù);3.包裝類可表示null值,用于區(qū)分未設(shè)置或缺失的數(shù)據(jù);4.包裝類提供字符串轉(zhuǎn)換等實(shí)用方法,便于數(shù)據(jù)解析與處理,因此在需要這些特性的場(chǎng)景下,包裝類不可或缺。

JIT編譯器如何優(yōu)化代碼? JIT編譯器如何優(yōu)化代碼? Jun 24, 2025 pm 10:45 PM

JIT編譯器通過方法內(nèi)聯(lián)、熱點(diǎn)檢測(cè)與編譯、類型推測(cè)與去虛擬化、冗余操作消除四種方式優(yōu)化代碼。1.方法內(nèi)聯(lián)減少調(diào)用開銷,將頻繁調(diào)用的小方法直接插入調(diào)用處;2.熱點(diǎn)檢測(cè)識(shí)別高頻執(zhí)行代碼并集中優(yōu)化,節(jié)省資源;3.類型推測(cè)收集運(yùn)行時(shí)類型信息實(shí)現(xiàn)去虛擬化調(diào)用,提升效率;4.冗余操作消除根據(jù)運(yùn)行數(shù)據(jù)刪除無用計(jì)算和檢查,增強(qiáng)性能。

什么是接口中的靜態(tài)方法? 什么是接口中的靜態(tài)方法? Jun 24, 2025 pm 10:57 PM

StaticmethodsininterfaceswereintroducedinJava8toallowutilityfunctionswithintheinterfaceitself.BeforeJava8,suchfunctionsrequiredseparatehelperclasses,leadingtodisorganizedcode.Now,staticmethodsprovidethreekeybenefits:1)theyenableutilitymethodsdirectly

什么是實(shí)例初始器塊? 什么是實(shí)例初始器塊? Jun 25, 2025 pm 12:21 PM

實(shí)例初始化塊在Java中用于在創(chuàng)建對(duì)象時(shí)運(yùn)行初始化邏輯,其執(zhí)行先于構(gòu)造函數(shù)。它適用于多個(gè)構(gòu)造函數(shù)共享初始化代碼、復(fù)雜字段初始化或匿名類初始化場(chǎng)景,與靜態(tài)初始化塊不同的是它每次實(shí)例化時(shí)都會(huì)執(zhí)行,而靜態(tài)初始化塊僅在類加載時(shí)運(yùn)行一次。

變量的最終關(guān)鍵字是什么? 變量的最終關(guān)鍵字是什么? Jun 24, 2025 pm 07:29 PM

InJava,thefinalkeywordpreventsavariable’svaluefrombeingchangedafterassignment,butitsbehaviordiffersforprimitivesandobjectreferences.Forprimitivevariables,finalmakesthevalueconstant,asinfinalintMAX_SPEED=100;wherereassignmentcausesanerror.Forobjectref

什么是工廠模式? 什么是工廠模式? Jun 24, 2025 pm 11:29 PM

工廠模式用于封裝對(duì)象創(chuàng)建邏輯,使代碼更靈活、易維護(hù)、松耦合。其核心答案是:通過集中管理對(duì)象創(chuàng)建邏輯,隱藏實(shí)現(xiàn)細(xì)節(jié),支持多種相關(guān)對(duì)象的創(chuàng)建。具體描述如下:工廠模式將對(duì)象創(chuàng)建交給專門的工廠類或方法處理,避免直接使用newClass();適用于多類型相關(guān)對(duì)象創(chuàng)建、創(chuàng)建邏輯可能變化、需隱藏實(shí)現(xiàn)細(xì)節(jié)的場(chǎng)景;例如支付處理器中通過工廠統(tǒng)一創(chuàng)建Stripe、PayPal等實(shí)例;其實(shí)現(xiàn)包括工廠類根據(jù)輸入?yún)?shù)決定返回的對(duì)象,所有對(duì)象實(shí)現(xiàn)共同接口;常見變體有簡(jiǎn)單工廠、工廠方法和抽象工廠,分別適用于不同復(fù)雜度的需求。

什么是類型鑄造? 什么是類型鑄造? Jun 24, 2025 pm 11:09 PM

類型轉(zhuǎn)換有兩種:隱式和顯式。1.隱式轉(zhuǎn)換自動(dòng)發(fā)生,如將int轉(zhuǎn)為double;2.顯式轉(zhuǎn)換需手動(dòng)操作,如使用(int)myDouble。需要類型轉(zhuǎn)換的情況包括處理用戶輸入、數(shù)學(xué)運(yùn)算或函數(shù)間傳遞不同類型的值時(shí)。需要注意的問題有:浮點(diǎn)數(shù)轉(zhuǎn)整數(shù)會(huì)截?cái)嘈?shù)部分、大類型轉(zhuǎn)小類型可能導(dǎo)致數(shù)據(jù)丟失、某些語言不允許直接轉(zhuǎn)換特定類型。正確理解語言的轉(zhuǎn)換規(guī)則有助于避免錯(cuò)誤。

See all articles