当前位置: 首页 > 知识库问答 >
问题:

使用spring会话和spring云安全时,OAuth2Client上下文(spring-security-oauth2)未在Redis中持久化

董哲
2023-03-14

提前非常感谢您阅读此问题。

我正在使用:

  • spring-security-oauth2:2.0.7。发布
  • spring云安全:1.0.1。发布
  • spring会话:1.0.1。发布

并且在单点登录(@EnableOAuth2Sso)中使用Spring-会话(通过@EnableRedisHttpsession)时,会对Redis数据存储中的sping-secity-oAuth2的持久性产生疑问,反向代理(@EnableZuulProxy)网关。

在我看来,SessionScopedjdkdynamicaoproxiedDefaultOAuth2ClientContext是在org中创建的。springframework。云安全oauth2。客户OAuth2Client-TautoConfiguration未正确保存在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);
    }

}

在不使用@enableRedistpSession的情况下调试创建oauth2ClientContext显示(如预期的那样),bean将在每个客户端会话中实例化一次,并存储在HttpSession中。除了在SpringSecurityContext组织中存储OAuth2accessToken之外,还将重用此实例来存储获取的OAuth2BealerToken详细信息。springframework。安全果心身份验证

但是,一旦使用了@enableRedistpSession,将首先在会话创建时创建oauth2ClientContextbean,以后也会创建该bean(同时仍使用相同的客户端会话)。调试Redis客户端会话内容可确认会话创建未正确保存oauth2ClientContext

在我们检索OAuth2bearerToken(NO SpringContext, NO范围arget.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"

在我们检索到OAuth2bearerToken后(SpringContext持续存在,但NO范围arget.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"

如果我们现在尝试访问configurerZuul的路由之一(因此需要调用org.springframework.security.oauth2.client.DefaultOAuth2ClientContext#getAccessToken),将创建另一个oauth2ClientContext实例(因为它不会在Redis中持久化,并带有nullAccessToken)。

有趣的是,该实例稍后将在Redis中持久化(但由于不重新请求AccessToken,因此将持久化null实例):

~$ 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中的@enableRedistpSession注释。

我们是否应该忽略来自AutoConfiguration的org.springframework.cloud.security.oauth2.client.OAuth2ClientAutoConfiguration,并手动创建一个具有不同设置的oAuth2ClientContext,以在Redis中启用Spring会话持久性?如果是的话,你能提供一个例子吗?

否则:如何在Redis中持久化OAuth2Client上下文?

许多提前阅读这个问题的人试图帮助。

共有3个答案

夏侯昊明
2023-03-14

我偶然发现了这篇文章,我有完全相同的问题,有一些小的不同:

  • 我的应用程序不是Spring启动应用程序

然而,这可能会节省未来读者的一些时间,上述解决方案也适用于我。因为我没有使用Spring Boot,所以我将在这里发布解决方案,以便使用web.xml配置在非Spring Boot应用程序中应用。

“诀窍”是在网络上定义。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和其他网站的时间,那我的日子就好过多了。

宰父阳焱
2023-03-14

@dave-syer提示是正确的。

我在这里发布的配置,可以用来设置的请求ContextFilter和启用sping-security-oauth对象的sping-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;
    }
}
孟洋
2023-03-14

那里有一个已知的问题(https://github.com/spring-projects/spring-session/issues/129和https://github.com/spring-projects/spring-boot/issues/2637)。您可以通过添加一个Request estContextFilter来解决这个问题。

 类似资料:
  • 我正在使用Spring Boot、Spring Security性和spring会话(redis)构建spring REST web应用程序。我正在使用SpringCloud和zuul代理按照网关模式构建一个云应用程序。在这个模式中,我使用spring会话来管理redis中的HttpSession,并使用它来授权我的资源服务器上的请求。当执行更改会话权限的操作时,我希望更新该对象,以便用户不必注销

  • 我试图使用Spring Cloud的Zuul、Eureka和我自己的服务实现微服务架构。我有多个具有UI和服务的服务,每个服务都可以使用x509安全性对用户进行身份验证。现在我想把祖尔放在那些服务机构的前面。由于Zuul无法将客户端证书转发到后端,我认为下一个最好的方法是在Zuul的前门对用户进行身份验证,然后使用Spring会话在后端服务中复制他们的身份验证状态。我遵循了Dave Syer的教程

  • spring-security-oauth2和spring-security-oauth2-core在Spring中有什么区别?spring-securityoauth2是否被spring-securityoauth2-core所取代? spring-security-oauth2发布链接:http://repo.spring.io/release/org/springframework/secu

  • 我正在用Spring Boot测试一个微服务架构,但是当Spring Session试图从redis反序列化会话时出现了一个异常。 体系结构如下: 雷迪斯 雷迪斯 网关 网关应用程序.yml 管理 我得到了以下堆栈跟踪。我注意到网关应用程序可以正确反序列化,但它在异常点使用DefaultListableBeanFactory。但Admin应用程序使用此StaticListableBeanFacto

  • 我正在使用一个Spring Boot+Spring Security OAuth2应用程序,我相信它的灵感来自Dave Syer的示例。应用程序被配置为OAuth2授权服务器,具有使用资源所有者密码凭据流的单个公共客户端。成功的令牌被配置为JWT。 公共Angular客户机向/oauth/token发送一个POST请求,该请求带有包含客户机id和秘密的基本身份验证头(这是让客户机进行身份验证的最简

  • 我正在使用Spring云安全和Oauth2来保护我的微服务。现在Pom如下: http://maven.apache.org/xsd/maven-4.0.0.xsd" Spring靴主要等级如下: 授权服务器配置如下: 注意:身份验证管理器自动连接到授权配置中 在下面的类中,身份验证管理器被配置并返回为abean,以便可以自动连接到上面的类: 现在application.properties如下: