spring-boot - Spring session : How to create separate session management policies for different URLs

标签 spring-boot spring-security spring-session

在使用spring session的spring boot项目中,如何针对不同的URL配置两种 session 管理策略?

  1. 对于 Angular 前端,我想使用默认实现并创建 X-Auth-Token token (如果需要,则创建 session )
  2. 但是对于公开​​的 API 端点,我想使用无状态 session 管理

我尝试了以下配置,但根本没有创建 session 。我认为第二个 block 正在覆盖 sessionCreationPolicy 因为它位于末尾

SecurityConfig.java

@Override
    public void configure(HttpSecurity http) throws Exception
    {


//Requests from angular app
http.authorizeRequests()
        .antMatchers("/", "/login","/api/v1/user/login", "/api/v1/user/authenticate", "/api/v1/user/logout", "/api/v1/health/find/status").permitAll()
        .antMatchers("/api/v1/person/**").hasAnyAuthority(ROLE_USER)
        .and()
        .httpBasic()
        .and()
    .exceptionHandling().authenticationEntryPoint(customBasicAuthenticationEntryPoint)
        .and()
        .logout()
        .invalidateHttpSession(true).clearAuthentication(true)
        .and().sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED);

//Requests from external systems
http.authorizeRequests()
        .antMatchers("/api/v1/external/**").hasAnyAuthority(ROLE_API_USER)
        .and().sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS);

}

更新

为 API 端点和 Angular 应用程序添加了自定义 WebSecurity 配置器适配器,如下所示。添加此后,API端点不会创建 session ,但Angular HTTP请求也不会创建 session

@Configuration
@EnableWebSecurity
public class SecurityConfig
{
 ....

    @Configuration
    @Order(1)
    public class ExternalApiSecurityConfig extends WebSecurityConfigurerAdapter
    {
        @Autowired
        public void configureGlobal(AuthenticationManagerBuilder auth)
        {
            auth.authenticationProvider(activeDirectoryLdapAuthenticationProvider()).eraseCredentials(true);
        }

        @Override
        public void configure(HttpSecurity http) throws Exception
        {
            http.authorizeRequests()
                    .antMatchers("/api/v1/search/**").hasAnyAuthority(ROLE_API_USER, ROLE_SYS_ADMIN)
                    .and()
                    .httpBasic()
                    .and()
                    .exceptionHandling().authenticationEntryPoint(customBasicAuthenticationEntryPoint)
                    .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

            http.headers()
                    .frameOptions().disable();

            // Uses CorsConfigurationSource bean defined below
            http.cors().configurationSource(corsConfigurationSource());

            http.csrf().disable();
        }
    }

    @Configuration
    @Order(2)
    public class DefaultSecurityConfig extends WebSecurityConfigurerAdapter
    {
        @Bean(BeanIds.AUTHENTICATION_MANAGER)
        @Override
        public AuthenticationManager authenticationManagerBean() throws Exception
        {
            return super.authenticationManagerBean();
        }

        @Override
        public void configure(WebSecurity webSecurity)
        {
            webSecurity.ignoring().antMatchers("/static/**");
        }

        @Override
        public void configure(HttpSecurity http) throws Exception
        {
    http.authorizeRequests()
        .antMatchers("/", "/login","/api/v1/user/login", "/api/v1/user/authenticate", "/api/v1/user/logout", "/api/v1/health/find/status").permitAll()
        .antMatchers("/api/v1/person/**").hasAnyAuthority(ROLE_USER)
        .and()
        .httpBasic()
        .and()
    .exceptionHandling().authenticationEntryPoint(customBasicAuthenticationEntryPoint)
        .and()
        .logout()
        .invalidateHttpSession(true).clearAuthentication(true)
        .and().sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED);
        }

        @Autowired
        public void configureGlobal(AuthenticationManagerBuilder auth)
        {
            auth.authenticationProvider(activeDirectoryLdapAuthenticationProvider()).eraseCredentials(true);
            auth.authenticationProvider(getDaoAuthenticationProvider()).eraseCredentials(true);
        }

    }
 ....
}

最佳答案

当您创建 WebSecurityConfigurerAdapter 时,您需要创建两个不同的过滤器链您正在创建一个包含所需安全 http 过滤器的代理过滤器链。

如果您查找DefaultSecurityFilterChain,您应该能够在启动时看到这一点在日志中,您应该再次看到类似 Creating filter chain: any request, [Filters...] 的日志记录语句

DefaultSecurityFilterChain默认情况下,任何请求( /** )都会通过它。为了能够将请求分离到不同的过滤器链,您需要创建第二个 WebSecurityConfigurerAdapter ,将其范围限制为任何路径,并将您想要的配置应用到每个路径。

一个问题是您还需要对适配器应用更高的优先级,最终代码看起来像这样。

  @Order(Ordered.HIGHEST_PRECEDENCE + 1)
    @Configuration
    public static class ApiSecurity extends WebSecurityConfigurerAdapter {
        @Override
        protected void configure(final HttpSecurity http) throws Exception {
            http.antMatcher("/api/v1/external/**")
                    .authorizeRequests()
                    .anyRequest()
                    .hasAnyAuthority(ROLE_API_USER)
                    .and()
                    .sessionManagement()
                    .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        }
    }

    @Order(Ordered.HIGHEST_PRECEDENCE + 2)
    @Configuration
    public static class DefaultSecurityFilter extends WebSecurityConfigurerAdapter {
        @Override
        protected void configure(final HttpSecurity http) throws Exception {
            //Requests from angular app
            http.authorizeRequests()
                    .antMatchers("/", "/login","/api/v1/user/login", "/api/v1/user/authenticate", "/api/v1/user/logout", "/api/v1/health/find/status").permitAll()
                    .antMatchers("/api/v1/person/**").hasAnyAuthority(ROLE_USER)
                    .and()
                    .httpBasic()
                    .and()
                    .exceptionHandling().authenticationEntryPoint(customBasicAuthenticationEntryPoint)
                    .and()
                    .logout()
                    .invalidateHttpSession(true).clearAuthentication(true)
                    .and().sessionManagement()
                    .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED);
        }
    }

在此之后您应该看到两个 DefaultSecurityFilterChain在日志中创建,第一个是 "/api/v1/external/**"第二个any request捕获任何其他请求。

关于spring-boot - Spring session : How to create separate session management policies for different URLs,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63262262/

相关文章:

spring - Spring Boot session 超时不起作用?

spring - HikariCP 在 "mvn spring-boot:run"时启动,但没有可部署的 war 文件

java - Spring Boot 组件扫描

java - 嵌入式 Jetty 环境中的 Spring Boot 和 Spring Security 集成

java - 当从 Atmosphere 的 MeteorServlet 中使用 Spring DispatcherServlet 时,Spring 上下文会加载两次

Spring Session 不适用于 Sitemesh

Spring Boot 2 和 OAuth2/JWT 配置

spring - 如何配置Spring Boot和Spring Security同时支持表单登录和Google OAuth2登录

spring - 是否可以在没有 Redis 的情况下使用 Spring Boot session ?

configuration - 如何在没有 Redis 且没有自动配置的情况下使用 spring-boot 配置 spring-session 以使用另一个数据库存储