Spring 会话:如何为不同的 URL 创建单独的会话管理策略
Spring Session: How to create separate session management policies for different URLs
在使用spring会话的spring引导项目中,如何为不同的URL配置两个会话管理策略?
- 对于 Angular 前端,我想使用默认实现并创建
X-Auth-Token
令牌(如果需要则创建会话)
- 但对于公开的 API 端点,我想使用无状态会话管理
我尝试了以下配置,但根本没有创建会话。我认为第二个块正在覆盖 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 端点不创建会话但 Angular HTTP 请求也不创建会话
@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会话的spring引导项目中,如何为不同的URL配置两个会话管理策略?
- 对于 Angular 前端,我想使用默认实现并创建
X-Auth-Token
令牌(如果需要则创建会话) - 但对于公开的 API 端点,我想使用无状态会话管理
我尝试了以下配置,但根本没有创建会话。我认为第二个块正在覆盖 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 端点不创建会话但 Angular HTTP 请求也不创建会话
@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
用于捕获任何其他请求。