在运行时延迟初始化 Spring Security + 重新加载 Spring Security 配置

Posted

技术标签:

【中文标题】在运行时延迟初始化 Spring Security + 重新加载 Spring Security 配置【英文标题】:Lazy initialise spring security at runtime + reload spring security configuration 【发布时间】:2021-10-20 04:23:39 【问题描述】:

Spring 通常在启动应用程序时急切地加载 Spring 安全配置。我将 OAuth 与 Spring Security 一起使用

我正在维护一个用于存储 SSO 相关值(如 jwk-url、client_id、client_secret)的配置表。这些值将由管理员用户通过 CRUD 在同一个 Spring Boot 应用程序中填充。

那么在Spring安全配置(refer below code - jwkSetUri(...))中就只有jwk-url可以配置了。这在应用程序启动时不可用。

所以我想在值加载到表后初始化spring安全配置,就像运行时的​​延迟加载(@Lazy)一样。我知道如何延迟加载常规类/服务。

    但我仍然不确定如何在运行时调用 configure(HttpSecurity http) 方法以及如何 p ass HttpSecurity 参数。当我尝试像在运行时延迟加载一样调用 new ResourceServerConfiguration() 时,我没有看到 configure() 方法被调用。 (或)此类需要在需要时作为 bean 和延迟加载进行维护。但仍然不确定如何在代码中调用 configure()。

    另一件事是如何在运行时刷新/重新加载 spring 安全配置,如果 JWK url 被管理员更改。那么只有spring security配置才能生效。

@Configuration
@EnableWebSecurity
public class ResourceServerConfiguration extends WebSecurityConfigurerAdapter 
    
    @Override
    public void configure(HttpSecurity http) throws Exception 
        http.cors()
                .and()
                .csrf().disable()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                .authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .oauth2ResourceServer()
                .authenticationEntryPoint(oAuth2AuthenticationEntryPoint)
                .accessDeniedHandler(oAuth2AccessDeniedHandler)
                .jwt()
                 // Some Auth server URL which would be fetch from table
                .jwkSetUri(ssoConfigService.getActiveSSOCertificateURL()); 
                 // Eg. http://localhost:8090/auth/realms/demo-app/protocol/openid-connect/certs
    

我已经参考了这些链接。但这对我的目的没有帮助。任何帮助将不胜感激。

How do I lazy load Spring Security?

How to reload the Configure method of WebSecurityConfigurerAdapter when the application is up and running

Modify Spring Security Config at Runtime

Configure Spring HTTP Security at Runtime

【问题讨论】:

【参考方案1】:

请检查此链接Customizing CORS Filtering at Runtime,其中包含与您相关的类似用例,但对他而言,他需要动态更改允许的来源。他们决定创建一个新过滤器并简单地扩展 OncePerRequestFilter。

请注意检查OAuth2ResourceServerProperties 是否适合您的用例。

更新: 在这种情况下尝试使用此代码:

另一件事是如何在运行时刷新/重新加载 spring 安全配置,如果 JWK url 被管理员更改。那么只有spring security配置才能生效。

 @Override
    public void configure(HttpSecurity http) throws Exception 
        http.cors()
                .and()
                .csrf().disable()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                .authorizeRequests()
                .anyRequest().authenticated()

                // TODO: test with and without this and check if work for you
                .and()
                .oauth2ResourceServer()
                .authenticationEntryPoint(oAuth2AuthenticationEntryPoint)
                .accessDeniedHandler(oAuth2AccessDeniedHandler)
                .jwt()
                // Some Auth server URL which would be fetch from table
                .jwkSetUri(ssoConfigService.getActiveSSOCertificateURL());
        // Eg. http://localhost:8090/auth/realms/demo-app/protocol/openid-connect/certs

        http.addFilterBefore(new OncePerRequestFilter() 
            // Every time a request occur, this method will be called.
            @Override
            protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException 

                try 
                    http.oauth2ResourceServer()
                            .authenticationEntryPoint(oAuth2AuthenticationEntryPoint)
                            .accessDeniedHandler(oAuth2AccessDeniedHandler)
                            .jwt()
                            // Some Auth server URL which would be fetch from table
                            .jwkSetUri(ssoConfigService.getActiveSSOCertificateURL());
                 catch (Exception e) 
                    e.printStackTrace();
                
            
        , BasicAuthenticationFilter.class);
    

希望这些信息对您有所帮助。

【讨论】:

感谢会检查。您还可以更新OAuth2ResourceServerProperties 的正确链接吗?您更新了两者的 cors 帮助链接。 还有一种方法可以在运行时(而不是在应用程序启动时)延迟初始化 spring 安全性,当我的配置表已被用户通过 API 调用填满时,之后我想用SSO 值和安全性应该生效。 @ARods,您的配置表是在您尝试实现 Spring Security 的同一个项目中还是在外部数据库中?您能否更好地解释用例的工作流程和架构,以更好地理解您想要做什么以及为什么需要像上面解释的那样以惰性方式初始化 Spring Security? 是的,我在同一个项目和同一个数据库中有配置表和 API,并且还使用 React JS 管理 UI。我希望管理员用户通过 API 更新 OAuth 配置,此时只有配置表会填充条目。然后只有我们可以拥有使用 OAuth 颁发者 URL 启动 Spring 安全性的值(否则应用程序将在启动时失败)。我最初没有颁发者 URL 值。这就是为什么我想在运行时而不是在应用程序启动时延迟加载 Spring Security。这可能吗? @ARods,如果您在填写数据库表后加载 Spring Security,您将如何保护“您为更新数据库中的 OAuth 配置而创建的管理员用户 API”?我想你会有一个用于 OAuth 管理配置的 API 和其他用于 ReactJS 应用程序的 API。

以上是关于在运行时延迟初始化 Spring Security + 重新加载 Spring Security 配置的主要内容,如果未能解决你的问题,请参考以下文章

HandlerInterceptorAdapter 在使用 Spring Security 登录时不运行

使用 Spring Security 在运行时切换身份验证方法?

Spring security:在运行时注册用户

Spring Security 在运行时动态添加/删除 antMatchers 和角色

如何在运行时将新用户添加到 Spring Security

在 docker 容器中运行可运行 jar 时,Grails Spring Security Active Directory 登录失败