Rumah > Java > javaTutorial > Keselamatan musim bunga pelayan Kebenaran Spring dengan perkhidmatan butiran pengguna tersuai untuk pengesahan dipacu data yang fleksibel

Keselamatan musim bunga pelayan Kebenaran Spring dengan perkhidmatan butiran pengguna tersuai untuk pengesahan dipacu data yang fleksibel

Susan Sarandon
Lepaskan: 2025-01-23 12:07:09
asal
599 orang telah melayarinya

Pelayan Kebenaran Spring

Spring Authorization Server ialah rangka kerja yang direka untuk melaksanakan spesifikasi OAuth 2.1 dan OpenID Connect 1.0, bersama-sama dengan piawaian lain yang berkaitan. Dibina pada Spring Security, ia menawarkan asas yang selamat, ringan dan boleh disesuaikan untuk mencipta Penyedia Identiti yang mematuhi penyelesaian OpenID Connect 1.0 dan Pelayan Kebenaran OAuth2.

Senarai Ciri

Apakah Spring Security dan bagaimana ia berfungsi?

jawapan ringkas
Spring Security ialah rangka kerja pengesahan dan kawalan akses yang berkuasa dan boleh disesuaikan. Ia adalah standard de-facto untuk mendapatkan aplikasi berasaskan Spring.

Pada asasnya, Spring Security pada asasnya ialah koleksi penapis servlet yang direka untuk meningkatkan aplikasi web anda dengan ciri pengesahan dan kebenaran yang mantap.

Spring Security juga bercantum dengan baik dengan rangka kerja seperti Spring Web MVC atau Spring Boot, menyokong standard seperti OAuth2 dan SAML. Ia menjana antara muka log masuk dan log keluar secara automatik serta melindungi aplikasi anda daripada kelemahan keselamatan biasa seperti CSRF.

Nah, itu tidak begitu membantu, bukan?

Mari kita mendalami keselamatan web untuk memahami perkara penting aliran kerja keselamatannya.

Untuk menjadi pakar Keselamatan Musim Bunga, anda mesti memahami tiga konsep teras ini dahulu:

  • Pengesahan
  • Keizinan
  • Penapis Servlet

Nota - Jangan memintas bahagian ini; ia meletakkan asas untuk semua fungsi Keselamatan Musim Bunga.

Pengesahan

Anda perlu mengakses akaun bank anda dalam talian untuk menyemak baki anda atau membuat transaksi. Biasanya ini dilakukan menggunakan Nama Pengguna dan Kata Laluan

Pengguna: "Saya John Doe. Nama pengguna saya ialah: johndoe1985."
Sistem Bank: "Sila sahkan identiti anda. Apakah kata laluan anda?"
Pengguna: "Kata laluan saya ialah: secureB@nk2023."
Sistem Bank: "Selamat datang, John Doe. Berikut ialah gambaran keseluruhan akaun anda."

Keizinan

Untuk aplikasi asas, pengesahan sahaja mungkin memadai: Setelah pengguna log masuk, mereka diberikan akses kepada semua kawasan aplikasi.

Walau bagaimanapun, dalam kebanyakan aplikasi, terdapat kebenaran atau peranan yang dimainkan.

Pengguna: "Biar saya bermain dengan transaksi itu …​."
Sistem Bank: "Sekejap, saya perlu menyemak kebenaran anda dahulu...​..ya Encik John Doe, anda mempunyai tahap pelepasan yang betul. Selamat mencuba."
Pengguna: "Saya akan pindahkan 1J ha ha ha …​ Gurau-gurau"

Penapis Servlet

Sekarang, mari kita terokai Penapis Servlet. Bagaimanakah ia berkaitan dengan pengesahan dan kebenaran?

Mengapa menggunakan Penapis Servlet?
Setiap aplikasi web Spring berkisar pada satu servlet: DispatcherServlet yang boleh dipercayai. Peranan utamanya ialah untuk menghalakan permintaan HTTP yang masuk (seperti dari penyemak imbas) kepada @Controller atau @RestController yang sesuai untuk pengendalian.

Inilah tawarannya: DispatcherServlet sendiri tidak mempunyai sebarang ciri keselamatan terbina dalam dan anda mungkin tidak mahu mengendalikan pengepala Pengesahan Asas HTTP mentah terus dalam @Controllers anda. Sebaik-baiknya, pengesahan dan kebenaran harus diurus sebelum permintaan sampai kepada @Controllers anda

Nasib baik, dalam persekitaran web Java, anda boleh mencapai ini dengan meletakkan penapis sebelum servlet. Ini bermakna anda boleh mempertimbangkan untuk mencipta SecurityFilter dan menyediakannya dalam Tomcat (bekas servlet/pelayan aplikasi) anda untuk memintas dan memproses setiap permintaan HTTP yang masuk sebelum ia mencapai servlet anda.

Security context

SecurityFilter mempunyai kira-kira 4 tugasan

  1. Pertama, penapis perlu mengekstrak nama pengguna/kata laluan daripada permintaan. Ia boleh melalui Pengepala HTTP Pengesahan Asas, atau medan borang, atau kuki, dsb.
  2. Kemudian penapis perlu mengesahkan gabungan nama pengguna/kata laluan itu terhadap sesuatu, seperti pangkalan data.
  3. Penapis perlu menyemak, selepas pengesahan berjaya, bahawa pengguna dibenarkan untuk mengakses URI yang diminta.
  4. Jika permintaan itu kekal dalam semua pemeriksaan ini, maka penapis boleh l dan permintaan itu dihantar ke DispatcherServlet anda, iaitu @Controllers anda.

Rantai Penapis

Secara praktiknya, kami akan memecahkan satu penapis kepada beberapa, yang kemudiannya akan anda pautkan bersama.

Begini cara permintaan HTTP masuk akan dihantar:

  1. Pertama, ia melalui LoginMethodFilter...
  2. Seterusnya, ia melalui Penapis Pengesahan...
  3. Kemudian, ia beralih ke Penapis Kebenaran...
  4. Dan akhirnya, ia mencapai servlet anda.

Persediaan ini dikenali sebagai Rantaian Penapis.

Dengan menggunakan penapis (atau rangkaian penapis), anda boleh mengurus semua cabaran pengesahan dan kebenaran dalam aplikasi anda dengan berkesan tanpa mengubah pelaksanaan teras @RestControllers atau @Controllers anda.

DefaultSecurityFilterChain Spring

Bayangkan anda telah mengkonfigurasi Spring Security dengan betul dan memulakan aplikasi web anda. Anda akan melihat mesej log yang kelihatan seperti ini:

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]|
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Memperluas satu baris itu mendedahkan bahawa Spring Security bukan sahaja menambah satu penapis—ia menyediakan keseluruhan rantai penapis dengan 15 (!) penapis berbeza.

Apabila permintaan HTTP tiba, ia melalui setiap satu daripada 15 penapis ini dalam urutan sebelum akhirnya mencapai @RestControllers anda. Susunan penapis ini adalah penting, kerana permintaan diproses dari bahagian atas rantai ke bahagian bawah.

security chain

Menganalisis Rantaian Penapis Spring

Menyelami butiran setiap penapis dalam rantai akan membawa kita terlalu jauh, tetapi berikut ialah penjelasan untuk beberapa penapis utama. Untuk pemahaman yang lebih mendalam tentang yang lain, anda boleh menerokai kod sumber Spring Security.

  1. Penapis Pengesahan Asas: Cuba untuk mencari Pengepala HTTP Pengesahan Asas pada permintaan dan jika ditemui, cuba untuk mengesahkan pengguna dengan nama pengguna dan kata laluan pengepala itu.
  2. UsernamePasswordAuthenticationFilter: Cuba mencari parameter permintaan nama pengguna/kata laluan/badan POST dan jika ditemui, cuba untuk mengesahkan pengguna dengan nilai tersebut.
  3. DefaultLoginPageGeneratingFilter: Menjana halaman log masuk untuk anda, jika anda tidak melumpuhkan ciri tersebut secara eksplisit. Penapis INI adalah sebab anda mendapat halaman log masuk lalai apabila mendayakan Spring Security.
  4. DefaultLogoutPageGeneratingFilter: Menjana halaman log keluar untuk anda, jika anda tidak melumpuhkan ciri tersebut secara eksplisit.
  5. FilterSecurityInterceptor: Adakah kebenaran anda.

bergurau

Soalan - Mengapa permintaan HTTP putus dengan penapis Spring Security?
Jawapan - Kerana setiap kali ia cuba mendekat, penapis berkata, "Tunggu! Biar saya periksa awak dulu!" ?

Ya rehat ........ Wah, tunggu... itu terlalu banyak cakap keselamatan untuk sekali gus!

Sediakan pelayan Keizinan Spring

Cara paling mudah untuk mula menggunakan Spring Authorization Server adalah dengan mencipta aplikasi berasaskan Spring Boot. Anda boleh menggunakan start.spring.io untuk menjana projek asas.

Satu-satunya kebergantungan yang diperlukan ialah pelaksanaan("org.springframework.boot:spring-boot-starter-oauth2-authorization-server")

Kami akan menambah dua lagi untuk melakukan lebih banyak tindakan

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]|
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Cara mengkonfigurasi Spring Security

Dengan versi Spring Security dan/atau Spring Boot terkini, cara untuk mengkonfigurasi Spring Security adalah dengan mempunyai kelas yang: Dianotasi dengan @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")
}
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

(1) : Rantaian penapis Spring Security untuk Titik Akhir Protokol.
(2) : Rantaian penapis Spring Security untuk pengesahan.
(3) : Contoh com.nimbusds.jose.jwk.source.JWKSource untuk menandatangani token akses.
(4) : Contoh JwtDecoder untuk menyahkod token akses bertandatangan.
(5) : Satu contoh AuthorizationServerSettings untuk mengkonfigurasi Spring Authorization Server.

Mari konfigurasikan CORS untuk membenarkan URL tertentu ke aplikasi kami

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]|
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

CorsConfiguration
Kelas ini digunakan untuk menentukan peraturan CORS. Dalam kes ini:

  • addAllowedOrigin("http://localhost:3000/"): Membenarkan permintaan daripada http://localhost:3000. Ini berguna untuk pembangunan tempatan apabila bahagian hadapan anda dijalankan pada port yang berbeza. Dalam pengeluaran, gantikan ini dengan domain sebenar anda.
  • addAllowedMethod("*"): Membenarkan semua kaedah HTTP (cth., GET, POST, PUT, DELETE, dll.).
  • addAllowedHeader("*"): Membenarkan semua pengepala HTTP dalam permintaan.

UrlBasedCorsConfigurationSource

  • Kelas yang memetakan corak URL (seperti /**) kepada konfigurasi CORS tertentu.
  • registerCorsConfiguration("/", konfigurasi): Menggunakan peraturan CORS yang ditetapkan (konfigurasi) pada semua titik akhir (/) dalam aplikasi.

Wah, banyak konfigurasi! Tetapi itulah keajaiban Rangka Kerja Musim Bunga—ia mengendalikan semua beban berat di belakang tabir.

Sudah tiba masanya untuk mengkonfigurasi Pelanggan

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")
}
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Beberapa perkara yang telah kami lakukan di atas

  1. clientId: Pengecam unik untuk membenarkan akses
  2. clientAuthenticationMethod : Mentakrifkan kaedah Pengesahan
  3. redirectUris Membenarkan hanya URL yang ditakrifkan
  4. authorizationGrantTypes authorization_code

UserDetailsService

UserDetailsService digunakan oleh DaoAuthenticationProvider untuk mendapatkan nama pengguna, kata laluan dan atribut lain untuk mengesahkan dengan nama pengguna dan kata laluan. Spring Security menyediakan pelaksanaan dalam memori, JDBC dan caching bagi UserDetailsService.

Anda boleh menentukan pengesahan tersuai dengan mendedahkan UserDetailsService tersuai sebagai kacang.

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

}
Salin selepas log masuk
Salin selepas log masuk

Setelah kami melancarkan aplikasi, persediaan OIDC dan OAuth2 kami dengan Pelayan Kebenaran Spring harus berfungsi dengan betul. Walau bagaimanapun, anda akan perasan kami telah menggunakan InMemoryUserDetailsManager, yang sesuai untuk tunjuk cara atau prototaip. Tetapi untuk persekitaran pengeluaran, ia tidak digalakkan kerana semua data hilang apabila aplikasi dimulakan semula.

JdbcUserDetailsManager dalam Keselamatan Musim Bunga

JdbcUserDetailsManager ialah ciri dalam Spring Security yang menggunakan JDBC untuk mengendalikan kelayakan dan peranan pengguna dengan menyambung ke pangkalan data hubungan. Ia sesuai apabila aplikasi anda boleh berfungsi dengan skema standard untuk jadual pengguna yang dijangkakan oleh Spring Security.

Skema yang tersedia daripada 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;
    }
}
Salin selepas log masuk
Salin selepas log masuk

Satu-satunya pelarasan diperlukan untuk beralih daripada InMemoryUserDetailsManager kepada 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]|
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Konfigurasi ini berkesan untuk aplikasi yang melekat pada skema jadual standard Spring Security. Tetapi, jika anda perlu menyesuaikan (seperti menggunakan e-mel untuk log masuk dan bukannya nama pengguna), melaksanakan UserDetailsService tersuai menawarkan kebolehsuaian yang diperlukan.

Custom UserDetailsService dengan Entiti Pelanggan

Mari tambahkan CustomUserDetailsService tersuai kepada pembekal. Dalam AuthenticationProvider tetapkan perkhidmatan tersuai menggunakan setUserDetailsService

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")
}
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Perkhidmatan tersuai

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

}
Salin selepas log masuk
Salin selepas log masuk

Repositori

@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;
    }
}
Salin selepas log masuk
Salin selepas log masuk

Entiti

@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);
    }
}
Salin selepas log masuk

Dalam penapis keselamatan kita perlu memberitahu keselamatan musim bunga untuk menggunakan perkhidmatan ini

.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();
}
Salin selepas log masuk

Kesimpulan

Di sini, anda mempunyai dua pilihan yang mantap untuk mengendalikan pengesahan:

  • JdbcUserDetailsManager: Pilihan yang mudah jika aplikasi anda sejajar dengan skema lalai Spring.
  • Perkhidmatan Butiran Pengguna Tersuai: Menyediakan fleksibiliti untuk mengurus medan dan peranan khas.

Tidak kira jika anda memilih JdbcUserDetailsManager atau memutuskan untuk melaksanakan UserDetailsService tersuai, kedua-duanya akan melengkapkan aplikasi anda dengan sistem pengesahan yang disokong pangkalan data berskala.

Atas ialah kandungan terperinci Keselamatan musim bunga pelayan Kebenaran Spring dengan perkhidmatan butiran pengguna tersuai untuk pengesahan dipacu data yang fleksibel. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

sumber:dev.to
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Artikel terbaru oleh pengarang
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan