ホームページ > Java > &#&チュートリアル > 柔軟なデータ駆動型認証のためのカスタム ユーザー詳細サービスを備えた Spring Authorization サーバー Spring セキュリティ

柔軟なデータ駆動型認証のためのカスタム ユーザー詳細サービスを備えた Spring Authorization サーバー Spring セキュリティ

Susan Sarandon
リリース: 2025-01-23 12:07:09
オリジナル
599 人が閲覧しました

Spring認可サーバー

Spring Authorization Server は、OAuth 2.1 および OpenID Connect 1.0 仕様、およびその他の関連標準を実装するように設計されたフレームワークです。 Spring Security 上に構築されており、OpenID Connect 1.0 および OAuth2 Authorization Server ソリューションに準拠した ID プロバイダーを作成するための、安全かつ軽量でカスタマイズ可能な基盤を提供します。

機能リスト

Spring Security とは何ですか?またどのように機能しますか?

短い答え
Spring Security は、強力で高度にカスタマイズ可能な認証およびアクセス制御フレームワークです。これは、Spring ベースのアプリケーションを保護するための事実上の標準です。

Spring Security の本質は、本質的に、堅牢な認証および認可機能で Web アプリケーションを強化するように設計されたサーブレット フィルターのコレクションです。

Spring Security は、Spring Web MVC や Spring Boot などのフレームワークともうまく連携し、OAuth2 や SAML などの標準をサポートします。ログインおよびログアウト インターフェイスを自動的に生成し、CSRF などの一般的なセキュリティ脆弱性からアプリケーションを保護します。

まあ、それはあまり役に立ちませんね?

Web セキュリティを詳しく調べて、セキュリティ ワークフローの本質を理解しましょう。

Spring Security のエキスパートになるには、まず次の 3 つの中心的な概念を理解する必要があります。

  • 認証
  • 承認
  • サーブレットフィルター

- このセクションを無視しないでください。これは、すべての Spring Security 機能の基礎を築きます。

認証

残高を確認したり取引を行ったりするには、オンラインで銀行口座にアクセスする必要があります。通常、これはユーザー名とパスワード

を使用して行われます。

ユーザー: 「私は John Doe です。ユーザー名は johndoe1985 です。」
銀行のシステム: 「本人確認を行ってください。パスワードは何ですか?」
ユーザー: 「私のパスワードは: secureB@nk2023 です。」
銀行のシステム: 「ようこそ、John Doe。これがあなたの口座概要です。」

認可

基本的なアプリケーションの場合、認証だけで十分な場合があります。ユーザーがログインすると、アプリケーションのすべての領域へのアクセスが許可されます。

ただし、ほとんどのアプリケーションでは、権限またはロールが有効になっています。

ユーザー: 「そのトランザクションで遊ばせてください…。」
銀行のシステム: 「ちょっと待って、最初にあなたの許可を確認する必要があります… ..はい、ジョン・ドゥさん、あなたは正しい許可レベルを持っています。楽しんでください。」
ユーザー: 「100万送金します、ははは… 冗談です」

サーブレットフィルター

それでは、サーブレット フィルターを見てみましょう。それらは認証と認可にどのように関係しますか?

サーブレット フィルターを使用する理由
すべての Spring Web アプリケーションは、信頼できる DispatcherServlet という単一のサーブレットを中心に展開します。その主な役割は、受信 HTTP リクエスト (ブラウザからのリクエストなど) を処理のために適切な @Controller または @RestController にルーティングすることです。

これが対処法です。DispatcherServlet 自体にはセキュリティ機能が組み込まれていないため、生の HTTP Basic Auth ヘッダーを @Controller で直接処理したくないでしょう。理想的には、認証と認可は、リクエストが @Controllers

に到達する前に処理されるべきです。

幸いなことに、Java Web 環境では、サーブレットの前にフィルターを配置することでこれを実現できます。これは、SecurityFilter を作成し、Tomcat (サーブレット コンテナ/アプリケーション サーバー) に設定して、サーブレットに到達する前にすべての受信 HTTP リクエストをインターセプトして処理することを検討できることを意味します。

Security context

SecurityFilter にはおよそ 4 つのタスクがあります

  1. まず、フィルターはリクエストからユーザー名/パスワードを抽出する必要があります。これは、Basic Auth HTTP ヘッダー、フォーム フィールド、Cookie などを介して行われる可能性があります。
  2. 次に、フィルターはそのユーザー名とパスワードの組み合わせをデータベースなどの何かと照合して検証する必要があります。
  3. フィルターは、認証が成功した後、ユーザーが要求された URI へのアクセスを許可されていることを確認する必要があります。
  4. リクエストがこれらすべてのチェックを通過した場合、フィルターは リクエストは DispatcherServlet、つまり @Controllers に送信されます。

フィルターチェーン

実際には、1 つのフィルターをいくつかに分割し、それらをリンクします。

受信 HTTP リクエストがどのように送信されるかを次に示します:

  1. まず、LoginMethodFilter を通過します...
  2. 次に、AuthenticationFilter を通過します...
  3. その後、AuthorizationFilter に移動します...
  4. そして最後に、サーブレットに到達します。

このセットアップはフィルターチェーンとして知られています。

フィルター (またはフィルターのチェーン) を使用すると、@RestControllers または @Controllers のコア実装を変更することなく、アプリケーション内のすべての認証および認可の課題を効果的に管理できます。

Spring の DefaultSecurityFilterChain

Spring Security を適切に構成し、Web アプリケーションを開始したと想像してください。次のようなログ メッセージが表示されます:

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]|
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

その 1 行を展開すると、Spring Security が 1 つのフィルターを追加するだけではなく、15 (!) の異なるフィルターを含むフィルター チェーン全体をセットアップしていることがわかります。

HTTP リクエストが到着すると、最終的に @RestControllers に到達する前に、これらの 15 の各フィルターを順番に通過します。リクエストはチェーンの先頭から最後まで処理されるため、これらのフィルターの順序は重要です。

security chain

Spring の FilterChain を分析する

チェーン内のすべてのフィルターの詳細を掘り下げると行き過ぎてしまいますが、ここではいくつかの主要なフィルターについて説明します。他のものをより深く理解するには、Spring Security のソース コードを調べてください。

  1. BasicAuthenticationFilter: リクエストで Basic Auth HTTP ヘッダーの検索を試み、見つかった場合は、ヘッダーのユーザー名とパスワードを使用してユーザーの認証を試みます。
  2. UsernamePasswordAuthenticationFilter: ユーザー名/パスワードのリクエスト パラメーター/POST 本体の検索を試み、見つかった場合は、それらの値を使用してユーザーの認証を試みます。
  3. DefaultLoginPageGeneratingFilter: 機能を明示的に無効にしない場合、ログイン ページを生成します。このフィルターは、Spring Security を有効にするときにデフォルトのログイン ページが表示される理由です。
  4. DefaultLogoutPageGeneratingFilter: ログアウト ページを生成します (その機能を明示的に無効にしない場合)。
  5. FilterSecurityInterceptor: 承認を行います。

ジョーク

質問 - HTTP リクエストが Spring Security フィルターで分割されたのはなぜですか?
答え - だって、近づこうとするたびにフィルターが「ちょっと待って!まず様子を見させてよ!」って言ってたから ?

はい、休憩....おっと、ちょっと待って...一度にしてはセキュリティの話が多すぎました!

Spring認可サーバーのセットアップ

Spring Authorization Server の使用を開始する最も簡単な方法は、Spring Boot ベースのアプリケーションを作成することです。 start.spring.io を使用して基本プロジェクトを生成できます。

必要な依存関係は、implementation("org.springframework.boot:spring-boot-starter-oauth2-authorization-server") だけです

さらにアクションを実行するために、さらに 2 つを追加します

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 を構成するには、次のクラスを使用します。 @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) : プロトコル エンドポイントの Spring Security フィルター チェーン。
(2) : 認証用の Spring Security フィルター チェーン。
(3) : アクセス トークンに署名するための com.nimbusds.jose.jwk.source.JWKSource のインスタンス。
(4) : 署名されたアクセス トークンをデコードするための JwtDecoder のインスタンス。
(5) : Spring Authorization Server を構成するための AuthorizationServerSettings のインスタンス。

アプリケーションへの特定の URL を許可するように CORS を構成してみましょう

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]|
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

CorsConfiguration
このクラスは、CORS ルールを定義するために使用されます。この場合:

  • addAllowedOrigin("http://localhost:3000/"): http://localhost:3000 からのリクエストを許可します。これは、フロントエンドが別のポートで実行されている場合のローカル開発に役立ちます。運用環境では、これを実際のドメインに置き換えます。
  • addAllowedMethod("*"): すべての HTTP メソッド (GET、POST、PUT、DELETE など) を許可します。
  • addAllowedHeader("*"): リクエスト内のすべての HTTP ヘッダーを許可します。

UrlBasedCorsConfigurationSource

  • URL パターン (/** など) を特定の CORS 構成にマップするクラス。
  • registerCorsConfiguration("/",configuration): 定義された CORS ルール (構成) をアプリケーション内のすべてのエンドポイント (/) に適用します。

わあ、たくさんの設定がありますね!しかし、それが Spring Framework の魔法です。舞台裏ですべての重労働を処理します。

クライアントを構成する時が来ました

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: アクセスを許可する一意の識別子
  2. clientAuthenticationMethod : 認証方法の定義
  3. redirectUris 定義された URL のみを許可します
  4. authorizationGrantTypes authorization_code

ユーザー詳細サービス

UserDetailsS​​ervice は、ユーザー名パスワード、およびユーザー名とパスワードで認証するためのその他の属性を取得するために DaoAuthenticationProvider によって使用されます。 Spring Security は、UserDetailsS​​ervice のインメモリ、JDBC、およびキャッシュ実装を提供します。

カスタム UserDetailsS​​ervice を Bean として公開することで、カスタム認証を定義できます。

InMemoryUserDetailsManager

@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();
    }

}
ログイン後にコピー
ログイン後にコピー

アプリケーションを起動すると、Spring Authorization Server を使用した OIDC および OAuth2 セットアップが正しく機能するはずです。ただし、デモやプロトタイピングには適した InMemoryUserDetailsManager を採用していることに気づくでしょう。ただし、運用環境では、アプリケーションの再起動時にすべてのデータが消えるため、これはお勧めできません。

Spring SecurityのJdbcUserDetailsManager

JdbcUserDetailsManager は、JDBC を使用してリレーショナル データベースに接続することでユーザーの資格情報とロールを処理する Spring Security 内の機能です。アプリケーションが Spring Security が期待するユーザー テーブルの標準スキーマを操作できる場合に理想的です。

Spring security org/springframework/security/core/userdetails/jdbc/users.ddl から入手可能なスキーマ

@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 から JdbcUserDetailsManager に移行するために必要な唯一の調整

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 の標準テーブル スキーマに準拠するアプリケーションに効果的です。ただし、カスタマイズする必要がある場合 (ユーザー名の代わりにログインに電子メールを使用するなど)、カスタム UserDetailsS​​ervice を実装すると、必要な適応性が得られます。

Customer エンティティを使用したカスタム UserDetailsS​​ervice

カスタム CustomUserDetailsS​​ervice をプロバイダーに追加しましょう。 AuthenticationProvider で、setUserDetailsS​​ervice
を使用してカスタム サービスを設定します。

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")
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

カスタムサービス

@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();
    }

}
ログイン後にコピー
ログイン後にコピー

リポジトリ

@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;
    }
}
ログイン後にコピー
ログイン後にコピー

エンティティ

@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 にこのサービスを使用するように指示する必要があります

.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();
}
ログイン後にコピー

結論

ここでは、認証を処理するための 2 つの強力な選択肢があります。

  • JdbcUserDetailsManager: アプリケーションが Spring のデフォルト スキーマに準拠している場合の簡単なオプションです。
  • Custom UserDetailsS​​ervice: 特別なフィールドとロールを管理する柔軟性を提供します。

JdbcUserDetailsManager を選択するか、カスタム UserDetailsS​​ervice を実装することに決定するかに関係なく、どちらもアプリケーションにスケーラブルなデータベース サポートの認証システムを装備します。

以上が柔軟なデータ駆動型認証のためのカスタム ユーザー詳細サービスを備えた Spring Authorization サーバー Spring セキュリティの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:dev.to
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート