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
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:
Nota - Jangan memintas bahagian ini; ia meletakkan asas untuk semua fungsi Keselamatan Musim Bunga.
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."
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"
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.
SecurityFilter mempunyai kira-kira 4 tugasan
Secara praktiknya, kami akan memecahkan satu penapis kepada beberapa, yang kemudiannya akan anda pautkan bersama.
Begini cara permintaan HTTP masuk akan dihantar:
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.
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]|
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.
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.
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!
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]|
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") }
(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]|
CorsConfiguration
Kelas ini digunakan untuk menentukan peraturan CORS. Dalam kes ini:
UrlBasedCorsConfigurationSource
Wah, banyak konfigurasi! Tetapi itulah keajaiban Rangka Kerja Musim Bunga—ia mengendalikan semua beban berat di belakang tabir.
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") }
Beberapa perkara yang telah kami lakukan di atas
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.
@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(); } }
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 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; } }
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]|
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.
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") }
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(); } }
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; } }
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); } }
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(); }
Di sini, anda mempunyai dua pilihan yang mantap untuk mengendalikan pengesahan:
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!