在Spring中使用多个HttpSessionIdResolver。
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在Spring中使用多个HttpSessionIdResolver。相关的知识,希望对你有一定的参考价值。
我想对位于 "api**"下的所有内容使用HTTPSessionIdResolver,对其他内容使用标准CookieResolver。
如何才能做到这一点,使两个配置使用不同的解析器?在我目前的方法中,所有的东西都使用X-AUTH。
我试图了解Spring内部的实现,我最终在SessionRepositoryFilter中,但这个过滤器只有一个实例被创建,所以der只存在一个resolver。
@EnableWebSecurity
public class TestConfig {
@EnableSpringHttpSession
@Configuration
@Order(1)
public static class Abc extends WebSecurityConfigurerAdapter {
@Bean
@Primary
public HeaderHttpSessionIdResolver xAuth() {
return HeaderHttpSessionIdResolver.xAuthToken();
}
@Bean
@Primary
public MapSessionRepository mapSessionRepository(){
return new MapSessionRepository(new HashMap<>());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/service/json/**")
.authorizeRequests()
.anyRequest().authenticated()
.and()
.httpBasic()
.and()
.csrf()
.disable();
}
}
@EnableSpringHttpSession
@Configuration
@Order(2)
public static class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@ConfigurationProperties(prefix = "spring.datasource")
@Bean
@Primary
public DataSource dataSource() {
return DataSourceBuilder
.create()
.build();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/css/**", "/user/registration", "/webfonts/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
@Bean
public BCryptPasswordEncoder bcrypt() {
return new BCryptPasswordEncoder();
}
@Bean
public JdbcUserDetailsManager userDetailsManager() {
JdbcUserDetailsManager manager = new UserDetailsManager(dataSource());
manager.setUsersByUsernameQuery("select username,password,enabled from users where username=?");
manager.setAuthoritiesByUsernameQuery("select username,authority from authorities where username = ?");
return manager;
}
@Autowired
public void initialize(AuthenticationManagerBuilder builder) throws Exception {
builder.userDetailsService(userDetailsManager()).passwordEncoder(bcrypt());
}
}
}
我可以将逻辑移动到一个resolver中,将工作委托给现有的resolver,但这似乎是黑客?
public class SmartHttpSessionIdResolver implements HttpSessionIdResolver {
private static final String HEADER_X_AUTH_TOKEN = "X-Auth-Token";
private static final CookieHttpSessionIdResolver cookie = new CookieHttpSessionIdResolver();
private static final HeaderHttpSessionIdResolver xauth = HeaderHttpSessionIdResolver.xAuthToken();
@Override
public List<String> resolveSessionIds(HttpServletRequest request) {
if (isXAuth(request)) {
return xauth.resolveSessionIds(request);
}
return cookie.resolveSessionIds(request);
}
@Override
public void setSessionId(HttpServletRequest request, HttpServletResponse response, String sessionId) {
if (isXAuth(request)) {
xauth.setSessionId(request, response, sessionId);
} else {
cookie.setSessionId(request, response, sessionId);
}
}
@Override
public void expireSession(HttpServletRequest request, HttpServletResponse response) {
if (isXAuth(request)) {
xauth.expireSession(request, response);
} else {
cookie.expireSession(request, response);
}
}
private boolean isXAuth(HttpServletRequest request) {
return request.getHeader(HEADER_X_AUTH_TOKEN) != null;
}
}
正如你上面提到的,基于""的代码。SessionRepositoryFilter"类,很明显它只支持一个 "HttpSessionIdResolver"。因此,如果你只使用一个 "SessionRepositoryFilter",你的唯一选择似乎就是你建议的那个。虽然这样做也可以,但感觉有点黑,而且,如果你的要求确实是对所有位于 "api**"下的东西都使用 "HTTPSessionIdResolver",那么也不能保证。
由于 "SessionRepositoryFilter "类实际上是一个Filter,我建议检查你是否可以为 "SessionRepositoryFilter "类创建两个Spring Bean。一个将用于 "api*"模式下的所有HTTP端点,另一个用于所有其他路径。然后,你可以分别使用 "HttpSessionIdResolver "和 "CookieSessionIdResolver"。你可以找到一个基于URL模式定义不同过滤器的例子。此处.
在尝试了问题中提供的解决方案后(说实话,效果还不错),我也尝试通过提供两个不同的过滤器来实现。然而,当 @EnableSpringHttpSession
加了一个 SessionRepositoryFilter
是自动添加的,而在servlet过滤器链中再添加两个这样的过滤器似乎很奇怪。因此,我认为它们必须放在安全过滤器链中,这是很好的,因为这样我们也可以使用在那里做的URL匹配(而不是在其他地方也要实现)。
由于其他安全过滤器使用的是 HttpSession
,我们必须手动将 SessionRepositoryFilter
链条中的第一个。这是我想出的办法(在Kotlin中),对我来说效果很好。
@EnableWebSecurity
class SecurityConfig() {
private val sessionStore = ConcurrentHashMap<String, Session>()
private val sessionRepo = MapSessionRepository(sessionStore)
@Configuration
@Order(1)
inner class XAuthConfig(): WebSecurityConfigurerAdapter() {
override fun configure(http: HttpSecurity) {
http
.requestMatchers()
.antMatchers("/api**")
.and()
.addFilterBefore(
SessionRepositoryFilter(sessionRepo).apply{
setHttpSessionIdResolver(
HeaderHttpSessionIdResolver.xAuthToken();
)
}, WebAsyncManagerIntegrationFilter::class.java)
}
}
@Configuration
@Order(2)
inner class DefaultConfig(): WebSecurityConfigurerAdapter() {
override fun configure(http: HttpSecurity) {
http
.addFilterBefore(
SessionRepositoryFilter(sessionRepo).apply{
setHttpSessionIdResolver(
CookieHttpSessionIdResolver()
)
}, WebAsyncManagerIntegrationFilter::class.java)
}
}
}
}
注 该注释 @EnableSpringHttpSession
已被删除。相反,我们增加了 SessionRepositoryFilter
的前的手动。WebAsyncManagerIntegrationFilter
s(安全过滤器链中的第一个过滤器)。的功能。SessionRepositoryFilter
是为了取代现有的 HttpSession
与春天的 HttpSession
无论我们是手动放置还是通过自动配置自动放置,它都会这样做。只要在安全过滤器链之前没有其他过滤器使用会话,就应该可以解决这个问题。否则,重新安排一些过滤器可能还是会有效果的。
以上是关于在Spring中使用多个HttpSessionIdResolver。的主要内容,如果未能解决你的问题,请参考以下文章
基于tomcat 7.0.68 的websocket 实现,及通过 HttpSessionId 实现websocket session 共享
如何在 Spring 中使用多个 ViewResolver?