非常感谢您阅读此问题。
设置
我在用:
spring-security-oauth2:2.0.7.RELEASE
spring-cloud-security:1.0.1.RELEASE
spring-session:1.0.1.RELEASE
并且在单点登录 ( )、反向代理 ( ) 网关中使用(via )spring-security-oauth2
OAuth2ClientContext
时,会对 Redis 数据存储中的持久性有疑问。spring-session
@EnableRedisHttpSession
@EnableOAuth2Sso
@EnableZuulProxy
问题
在我看来,创建的SessionScoped
JdkDynamicAopProxied没有正确地保存在 Redis 数据存储中。DefaultOAuth2ClientContext
org.springframework.cloud.security.oauth2.client.OAuth2ClientAutoConfiguration
@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
without的创建@EnableRedisHttpSession
表明(如预期的那样)bean 将在每个客户端会话中实例化一次并存储在HttpSession
. bearerToken
除了将 OAuth2 存储在accessToken
SpringSecurityContext
的org.springframework.security.core.Authentication
.
但是,一旦使用@EnableRedisHttpSession
,oauth2ClientContext
bean 将首先在会话创建时创建,稍后也会创建(同时仍使用相同的客户端会话)。调试 Redis 客户端会话内容确认oauth2ClientContext
会话创建未正确持久化:
在我们检索 OAuth2 bearerToken
(NO SpringContext, NO 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 持续存在,但 NO 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
),将创建另一个实例oauth2ClientContext
(因为没有在 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 按预期工作,但是 bean 在 Redis 中正确持久化。
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;
}
}
例子
通过添加以下依赖项,可以在OAuth2 反向代理网关的@dave-syer 示例中重现所描述的问题:
<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>
以及UiApplication@EnableRedisHttpSession
中的注释。
问题
我们是否应该忽略org.springframework.cloud.security.oauth2.client.OAuth2ClientAutoConfiguration
AutoConfiguration 并手动创建oauth2ClientContext
一个不同的设置以spring-session
在 Redis 中启用持久性?如果是这样,你能举个例子吗?
否则:如何oauth2ClientContext
在 Redis 中持久化?
提前向任何阅读此问题的人提供帮助。