首页 > Java > java教程 > Spring 授权服务器 spring security 具有自定义用户详细信息服务,用于灵活的数据驱动身份验证

Spring 授权服务器 spring security 具有自定义用户详细信息服务,用于灵活的数据驱动身份验证

Susan Sarandon
发布: 2025-01-23 12:07:09
原创
568 人浏览过

Spring授权服务器

Spring 授权服务器是一个旨在实现 OAuth 2.1 和 OpenID Connect 1.0 规范以及其他相关标准的框架。它基于 Spring Security 构建,为创建符合 OpenID Connect 1.0 和 OAuth2 授权服务器解决方案的身份提供者提供了安全、轻量级和可定制的基础。

功能列表

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

简短回答
Spring Security 是一个功能强大且高度可定制的身份验证和访问控制框架。它是保护基于 Spring 的应用程序的事实标准。

本质上,Spring Security 本质上是 servlet 过滤器的集合,旨在通过强大的身份验证和授权功能来增强您的 Web 应用程序。

Spring Security 还与 Spring Web MVC 或 Spring Boot 等框架很好地配合,支持 OAuth2 和 SAML 等标准。它自动生成登录和注销接口,并保护您的应用程序免受 CSRF 等常见安全漏洞的影响。

嗯,这不是很有帮助,不是吗?

让我们深入研究网络安全,以掌握其安全工作流程的要点。

要成为Spring Security专家,首先要掌握这三个核心概念:

  • 身份验证
  • 授权
  • Servlet 过滤器

注意 - 不要绕过此部分;它为所有 Spring Security 功能奠定了基础。

验证

您需要在线访问您的银行账户以查看余额或进行交易。通常这是使用用户名和密码完成的

用户:“我是 John Doe。我的用户名是:johndoe1985。”
银行系统:“请验证您的身份。您的密码是多少?”
用户:“我的密码是:secureB@nk2023。”
银行系统:“欢迎,John Doe。这是您的帐户概览。”

授权

对于基本应用程序,仅进行身份验证就足够了:用户登录后,他们将被授予访问应用程序所有区域的权限。

但是,在大多数应用程序中,都有权限或角色在发挥作用。

用户:“让我来玩一下该交易......”
银行系统:“等一下,我需要先检查您的权限……是的,John Doe 先生,您的权限级别正确。尽情享受吧。”
用户:“我转1M哈哈哈……​开玩笑开玩笑”

小服务程序过滤器

现在,让我们探索 Servlet 过滤器。它们与身份验证和授权有何关系?

为什么使用 Servlet 过滤器?
每个 Spring Web 应用程序都围绕一个 servlet 展开:值得信赖的 DispatcherServlet。它的主要作用是将传入的 HTTP 请求(例如来自浏览器的请求)路由到适当的 @Controller 或 @RestController 进行处理。

事情是这样的:DispatcherServlet 本身没有任何内置的安全功能,并且您可能不想直接在 @Controller 中处理原始 HTTP Basic Auth 标头。理想情况下,在请求到达您的 @Controllers

之前就应该处理身份验证和授权

幸运的是,在 Java Web 环境中,您可以通过在 servlet 之前放置过滤器来实现这一点。这意味着您可以考虑创建一个 SecurityFilter 并将其设置在 Tomcat(servlet 容器/应用程序服务器)中,以在每个传入的 HTTP 请求到达您的 servlet 之前拦截和处理它。

Security context

SecurityFilter 大约有 4 个任务

  1. 首先,过滤器需要从请求中提取用户名/密码。它可以通过基本身份验证 HTTP 标头、表单字段或 cookie 等实现。
  2. 然后过滤器需要根据数据库等内容验证用户名/密码组合。
  3. 过滤器需要在身份验证成功后检查用户是否有权访问所请求的 URI。
  4. 如果请求通过了所有这些检查,那么过滤器就可以 让请求传递到您的 DispatcherServlet,即您的 @Controllers。

过滤器链

在实践中,我们会将一个过滤器分解为多个过滤器,然后您可以将它们链接在一起。

以下是传入 HTTP 请求的传输方式:

  1. 首先,它通过 LoginMethodFilter...
  2. 接下来,它会通过 AuthenticationFilter...
  3. 然后,它移动到 AuthorizationFilter...
  4. 最后,它到达您的 servlet。

此设置称为 FilterChain。

通过使用过滤器(或一系列过滤器),您可以有效地管理应用程序中的所有身份验证和授权挑战,而无需更改 @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]|
登录后复制
登录后复制
登录后复制
登录后复制

扩展这一行表明 Spring Security 不仅仅添加一个过滤器,它还设置了一个包含 15 个(!)不同过滤器的完整过滤器链。

当 HTTP 请求到达时,它会依次通过这 15 个过滤器中的每一个,然后最终到达您的 @RestControllers。这些过滤器的顺序至关重要,因为请求是从链的顶部到底部处理的。

security chain

分析 Spring 的 FilterChain

深入研究链中每个过滤器的细节会让我们走得太远,但这里是一些关键过滤器的解释。为了更深入地了解其他内容,您可以探索 Spring Security 的源代码。

  1. BasicAuthenticationFilter:尝试在请求中查找基本身份验证 HTTP 标头,如果找到,则尝试使用标头的用户名和密码对用户进行身份验证。
  2. UsernamePasswordAuthenticationFilter:尝试查找用户名/密码请求参数/POST 正文,如果找到,则尝试使用这些值对用户进行身份验证。
  3. DefaultLoginPageGenerateFilter:如果您没有明确禁用该功能,则会为您生成登录页面。这个过滤器就是您在启用 Spring Security 时获得默认登录页面的原因。
  4. DefaultLogoutPageGenerateFilter:如果您没有明确禁用该功能,则会为您生成一个注销页面。
  5. FilterSecurityInterceptor:是否经过您的授权。

开玩笑

问题 - 为什么 HTTP 请求会被 Spring Security 过滤器破坏?
回答 - 因为每次它试图靠近时,过滤器都会说:“等一下!让我先检查一下你!” ?

是的,休息......哇,等等......这一次的安全讨论太多了!

设置 Spring 授权服务器

开始使用 Spring 授权服务器的最简单方法是创建基于 Spring Boot 的应用程序。您可以使用start.spring.io生成一个基本项目。

唯一需要的依赖是实现(“org.springframework.boot:spring-boot-starter-oauth2-authorization-server”)

我们将添加另外两个来执行更多操作

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) : AuthorizationServerSettings 实例,用于配置 Spring Authorization Server。

让我们配置 CORS 以允许某些 URL 访问我们的应用程序

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规则。在这种情况下:

  • addAllowedOrigin("http://localhost:3000/"):允许来自 http://localhost:3000 的请求。当您的前端在不同端口上运行时,这对于本地开发非常有用。在生产中,将其替换为您的实际域。
  • addAllowedMethod("*"):允许所有 HTTP 方法(例如 GET、POST、PUT、DELETE 等)。
  • addAllowedHeader("*"):允许请求中的所有 HTTP 标头。

UrlBasedCorsConfigurationSource

  • 将 URL 模式(如 /**)映射到特定 CORS 配置的类。
  • registerCorsConfiguration("/", configuration):将定义的 CORS 规则(配置)应用于应用程序中的所有端点 (/)。

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

是时候配置客户端了

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 授权代码

用户详情服务

UserDetailsS​​ervice 由 DaoAuthenticationProvider 用于检索 用户名密码以及其他用于使用用户名和密码进行身份验证的属性。 Spring Security 提供了 UserDetailsS​​ervice 的内存、JDBC 和缓存实现。

您可以通过将自定义 UserDetailsS​​ervice 公开为 bean 来定义自定义身份验证。

内存中用户详细信息管理器

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

}
登录后复制
登录后复制

一旦我们启动应用程序,我们的 OIDC 和 OAuth2 设置与 Spring 授权服务器应该可以正常运行。但是,您会注意到我们使用了 InMemoryUserDetailsManager,它非常适合演示或原型设计。但对于生产环境,这是不可取的,因为应用程序重新启动后所有数据都会消失。

Spring Security 中的 JdbcUserDetailsManager

JdbcUserDetailsManager 是 Spring Security 中的一项功能,它使用 JDBC 通过连接到关系数据库来处理用户凭据和角色。当您的应用程序可以使用 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 可提供必要的适应性。

带有客户实体的自定义 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();
}
登录后复制

结论

在这里,您有两个强大的选择来处理身份验证:

  • JdbcUserDetailsManager:如果您的应用程序与 Spring 的默认架构一致,这是一个简单的选项。
  • 自定义 UserDetailsS​​ervice:提供管理特殊字段和角色的灵活性。

无论您选择 JdbcUserDetailsManager 还是决定实现自定义 UserDetailsS​​ervice,两者都将为您的应用程序配备可扩展的、数据库支持的身份验证系统。

以上是Spring 授权服务器 spring security 具有自定义用户详细信息服务,用于灵活的数据驱动身份验证的详细内容。更多信息请关注PHP中文网其他相关文章!

来源:dev.to
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板