谢谢你提前阅读了这个问题。
设置
我正在使用:
spring-security-oauth2:2.0.7.RELEASEspring-cloud-security:1.0.1.RELEASEspring-session:1.0.1.RELEASE当在单点登录( spring-security-oauth2 ) (@EnableOAuth2Sso)反向代理(@EnableZuulProxy)网关中使用spring-session (通过@EnableRedisHttpSession)时,会有一个关于在Redis数据存储中使用spring-session(通过@EnableRedisHttpSession)的持久性的问题。
问题
在我看来,在SessionScoped JdkDynamicAopProxied DefaultOAuth2ClientContext中创建的org.springframework.cloud.security.oauth2.client.OAuth2ClientAutoConfiguration并没有正确地保存在Redis数据存储中。
@Configuration
@ConditionalOnBean(OAuth2SsoConfiguration.class)
@ConditionalOnWebApplication
protected abstract static class SessionScopedConfiguration extends BaseConfiguration {
@Bean
@Scope(value = "session", proxyMode = ScopedProxyMode.INTERFACES)
public OAuth2ClientContext oauth2ClientContext() {
return new DefaultOAuth2ClientContext(accessTokenRequest);
}
}调试没有oauth2ClientContext的@EnableRedisHttpSession创建表明(如预期的)每个客户端会话将实例化bean一次,并将其存储在HttpSession中。然后,除了将OAuth2 accessToken存储在Spring SecurityContext的org.springframework.security.core.Authentication中之外,还将重用此实例来存储获取的OAuth2 accessToken详细信息。
但是,一旦使用@EnableRedisHttpSession,oauth2ClientContext bean将首先在会话创建时创建,但稍后也会创建(同时仍然使用相同的客户端会话)。调试Redis客户端会话内容可以确认会话创建没有正确地持久化oauth2ClientContext:
在检索OAuth2 bearerToken (没有SpringContext,没有scopedTarget.oauth2ClientContext)之前:
~$ redis-cli hkeys "spring:session:sessions:17c5e80b-390c-4fd6-b5f9-a6f225dbe8ea"
1) "maxInactiveInterval"
2) "sessionAttr:org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository.CSRF_TOKEN"
3) "lastAccessedTime"
4) "creationTime"
5) "sessionAttr:SPRING_SECURITY_SAVED_REQUEST"在我们检索到OAuth2 bearerToken之后(SpringContext持久化,但没有scopedTarget.oauth2ClientContext):
~$ redis-cli hkeys "spring:session:sessions:844ca2c4-ef2f-43eb-b867-ca6b88025c8b"
1) "sessionAttr:org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository.CSRF_TOKEN"
2) "lastAccessedTime"
3) "creationTime"
4) "sessionAttr:SPRING_SECURITY_LAST_EXCEPTION"
5) "sessionAttr:SPRING_SECURITY_CONTEXT"
6) "maxInactiveInterval"如果我们现在尝试访问配置者Zuul的路由之一(因此需要调用org.springframework.security.oauth2.client.DefaultOAuth2ClientContext#getAccessToken),则将创建的另一个实例(因为没有在Redis中持久化,并带有null AccessToken )。
有趣的是,这个实例稍后将被持久化到Redis中(但是null实例将被持久化,因为AccessToken不会被重新请求):
~$ redis-cli hkeys "spring:session:sessions:c7120835-6709-4c03-8d2c-98f830ed6104"
1) "sessionAttr:org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository.CSRF_TOKEN"
2) "sessionAttr:SPRING_SECURITY_LAST_EXCEPTION"
3) "sessionAttr:scopedTarget.oauth2ClientContext"
4) "sessionAttr:SPRING_SECURITY_CONTEXT"
5) "maxInactiveInterval"
6) "creationTime"
7) "lastAccessedTime"
8) "sessionAttr:org.springframework.web.context.request.ServletRequestAttributes.DESTRUCTION_CALLBACK.scopedTarget.oauth2ClientContext" 创建一个简单的ScopedProxyMode.TARGET_CLASS注入bean就像预期的那样正常工作,但是在Redis中正确地保存了这个bean。
public class HelloWorldService implements Serializable {
public HelloWorldService(){
System.out.println("HelloWorldService created");
}
private String name = "World";
public String getName(){
return name;
}
public void setName(String name){
this.name=name;
}
public String getHelloMessage() {
return "Hello " + this.name;
}
}
@Configuration
public class AppConfig {
private SecureRandom random = new SecureRandom();
@Bean
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public HelloWorldService myHelloService(){
HelloWorldService s = new HelloWorldService();
String name = new BigInteger(130, random).toString(32);
System.out.println("name = " + name);
s.setName(name);
System.out.println("Resource HelloWorldService created = " + s);
return s;
}
}示例
通过添加以下依赖项,可以在@dave示例中再现所描述的OAuth2 reverse proxy gateway问题:
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session</artifactId>
<version>1.0.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-redis</artifactId>
</dependency>以及@EnableRedisHttpSession在UiApplication中的注释。
问题
我们是否应该忽略来自org.springframework.cloud.security.oauth2.client.OAuth2ClientAutoConfiguration的AutoConfiguration,手动创建一个具有不同设置的oauth2ClientContext,以便在Redis中启用spring-session持久性?如果是的话,请你举一个例子好吗?
否则:如何在Redis中持久化oauth2ClientContext?
许多人事先向任何阅读这个问题的人试着帮忙。
发布于 2015-06-23 08:28:08
这里有一个已知的问题(https://github.com/spring-projects/spring-session/issues/129和https://github.com/spring-projects/spring-boot/issues/2637)。您可以通过添加一个RequestContextFilter来绕过它。
发布于 2015-06-29 06:23:01
@dave提示是正确的。
我在这里发布了可用于设置RequestContextFilter和启用spring-security-oauth对象的spring-session持久性的配置。万一能帮上忙..。
@Configuration
public class RequestContextFilterConfiguration {
@Bean
@ConditionalOnMissingBean(RequestContextFilter.class)
public RequestContextFilter requestContextFilter() {
return new RequestContextFilter();
}
@Bean
public FilterRegistrationBean requestContextFilterChainRegistration(
@Qualifier("requestContextFilter") Filter securityFilter) {
FilterRegistrationBean registration = new FilterRegistrationBean(securityFilter);
registration.setOrder(SessionRepositoryFilter.DEFAULT_ORDER + 1);
registration.setName("requestContextFilter");
return registration;
}
}发布于 2018-12-07 12:02:39
我偶然发现了这篇文章,我也有同样的问题,但也有一些细微的不同:
然而,这可能会节省一些时间的未来读者,上述解决方案也对我有效。由于我没有使用Spring,所以我将在这里发布解决方案,以便在使用web.xml配置的非Spring应用程序中应用。
“诀窍”是在web.xml中定义RequestContextFilter。就我的测试而言,我还没有看到让请求上下文过滤器驻留在请求上下文侦听器之外的任何边框效果。
重要的是过滤器的排序。您需要按照这个顺序在web.xml中定义过滤器:
所以,就像:
<filter>
<filter-name>springSessionRepositoryFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSessionRepositoryFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>requestContextFilter</filter-name>
<filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>requestContextFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>
org.springframework.web.filter.DelegatingFilterProxy
</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>如果这能帮你节省几个小时的时间去挖掘Stackoverflow和其他网站,那就让我很开心了。
https://stackoverflow.com/questions/30976624
复制相似问题