【发布时间】:2019-12-16 10:00:19
【问题描述】:
所以我已将我的应用程序从 spring-boot 1.5 更新到 spring-boot 2.0。当请求来自任何主机时,我能够使用 spring-boot 1.5 版本正确登录,但现在 Spring boot 2.0 的问题只是来自同一主机的请求正在工作,但来自不同主机的请求他们的会话正在改变。下面是我在 spring-boot 2.0 中的 spring 安全配置,它导致了这个问题。
package com.s4m.digiid.config;
import java.util.Arrays;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
import org.springframework.session.FindByIndexNameSessionRepository;
import org.springframework.session.Session;
import org.springframework.session.security.SpringSessionBackedSessionRegistry;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import com.s4m.digiid.handler.CustomAccessDeniedHandler;
import com.s4m.digiid.handler.CustomAuthFailureHandler;
import com.s4m.digiid.handler.LoginHandler;
import com.s4m.digiid.handler.LogoutHandler;
import com.s4m.digiid.service.impl.AuthenticationService;
import com.s4m.digiid.util.ApiConstants;
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
@EnableJpaRepositories(basePackages = "com.s4m.digiid.repository")
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private Environment env;
@Autowired
private LogoutHandler logoutHandler;
@Autowired
private LoginHandler loginHandler;
@Autowired
private CustomAuthFailureHandler customAuthFailure;
@Autowired
private CustomAccessDeniedHandler accessDeniedHandler;
@Autowired
private AuthenticationService authService;
@Value("${maximum.sessions}")
private Integer maxSessions;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(authService)
.passwordEncoder(passwordEncoder());
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Autowired
private FindByIndexNameSessionRepository<? extends Session> sessionRepository;
@Bean
public SpringSessionBackedSessionRegistry sessionRegistry() {
return new SpringSessionBackedSessionRegistry<>(this.sessionRepository);
}
@Bean
public SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new ConcurrentSessionControlAuthenticationStrategy(sessionRegistry());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers(ApiConstants.SWAGGER_DOC_API, ApiConstants.SWAGGER_CONFIG_UI, ApiConstants.SWAGGER_RESOURCES,
ApiConstants.SWAGGER_CONFIG, ApiConstants.SWAGGER_HTML_UI, ApiConstants.WEB_JARS, ApiConstants.FAVICON).permitAll()
.and().formLogin().successHandler(loginHandler).failureHandler(customAuthFailure)
.and().logout()
.logoutUrl("/appLogout")
.logoutSuccessHandler(logoutHandler)
.and().exceptionHandling()
.accessDeniedHandler(accessDeniedHandler)
.and().csrf().disable()
.cors().and()
.addFilterBefore(authenticationFilter(), UsernamePasswordAuthenticationFilter.class)
.sessionManagement().maximumSessions(maxSessions).sessionRegistry(sessionRegistry()).maxSessionsPreventsLogin(false);
}
@Bean
public AuthenticationFilter authenticationFilter() throws Exception {
AuthenticationFilter filter = new AuthenticationFilter();
filter.setAuthenticationManager(authenticationManagerBean());
filter.setAuthenticationFailureHandler(customAuthFailure);
filter.setAuthenticationSuccessHandler(loginHandler);
return filter;
}
@Bean
public CorsConfigurationSource corsConfigurationSource()
{
List<String> allowedClients = Arrays.asList(env.getProperty("digiid.allowed.clients").split(","));
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(allowedClients);
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "OPTIONS"));
configuration.setMaxAge(Long.parseLong("3600"));
configuration.setAllowedHeaders(Arrays.asList("X-Requested-With", "Origin", "Content-Type", "Accept", "Authorization,X-Auth-Token"));
configuration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
下面是 spring-boot 1.5 中运行良好的代码。
package com.s4m.digiid.config;
import java.util.Arrays;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import com.s4m.digiid.handler.CustomAccessDeniedHandler;
import com.s4m.digiid.handler.CustomAuthFailureHandler;
import com.s4m.digiid.handler.LoginHandler;
import com.s4m.digiid.handler.LogoutHandler;
import com.s4m.digiid.service.impl.AuthenticationService;
import com.s4m.digiid.util.ApiConstants;
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
@EnableRedisHttpSession
@EnableJpaRepositories(basePackages = "com.s4m.digiid.repository")
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private Environment env;
@Autowired
private LogoutHandler logoutHandler;
@Autowired
private LoginHandler loginHandler;
@Autowired
private CustomAuthFailureHandler customAuthFailure;
@Autowired
private CustomAccessDeniedHandler accessDeniedHandler;
@Autowired
private AuthenticationService authService;
@Autowired
private SpringSessionBackedSessionRegistry sessionRegistry;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(authService)
.passwordEncoder(passwordEncoder());
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers(ApiConstants.SWAGGER_DOC_API, ApiConstants.SWAGGER_CONFIG_UI, ApiConstants.SWAGGER_RESOURCES,
ApiConstants.SWAGGER_CONFIG, ApiConstants.SWAGGER_HTML_UI, ApiConstants.WEB_JARS, ApiConstants.FAVICON).permitAll()
.and().formLogin().successHandler(loginHandler).failureHandler(customAuthFailure)
.and().logout()
.logoutUrl("/appLogout")
.logoutSuccessHandler(logoutHandler)
.and().exceptionHandling()
.accessDeniedHandler(accessDeniedHandler)
.and().csrf().disable()
.cors().and()
.addFilterBefore(authenticationFilter(), UsernamePasswordAuthenticationFilter.class)
.sessionManagement().maximumSessions(1).sessionRegistry(sessionRegistry).maxSessionsPreventsLogin(false);
}
@Bean
public AuthenticationFilter authenticationFilter() throws Exception {
AuthenticationFilter filter = new AuthenticationFilter();
filter.setAuthenticationManager(authenticationManagerBean());
filter.setAuthenticationFailureHandler(customAuthFailure);
filter.setAuthenticationSuccessHandler(loginHandler);
return filter;
}
@Bean
public CorsConfigurationSource corsConfigurationSource()
{
List<String> allowedClients = Arrays.asList(env.getProperty("digiid.allowed.clients").split(","));
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(allowedClients);
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "OPTIONS"));
configuration.setMaxAge(Long.parseLong("3600"));
configuration.setAllowedHeaders(Arrays.asList("X-Requested-With", "Origin", "Content-Type", "Accept", "Authorization,X-Auth-Token"));
configuration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
【问题讨论】:
-
但是来自不同主机的请求他们的会话正在发生变化。发生了什么变化? ID 还是某个值?为什么会有这样的问题?
-
所以问题是如果我在同一台机器上托管客户端(角度应用程序)和 spring-boot 应用程序,我可以登录。但是,如果我在另一台机器上托管 UI(角度)并在另一台机器上托管 spring-boot 应用程序,我可以登录,但是 consective 请求具有不同的会话 ID,并且 spring-boot 正在抛出 session Invalid 错误,这正在发生升级到 spring-boot 2.0 后。
标签: spring-boot spring-security session-cookies spring-session