如何使用 Spring Session + Spring security xml 配置和多重安全过滤器

Posted

技术标签:

【中文标题】如何使用 Spring Session + Spring security xml 配置和多重安全过滤器【英文标题】:How to use Spring Session + Spring security xml configuration and multiply security filter 【发布时间】:2015-12-04 05:35:58 【问题描述】:

背景

大家好, 我们有使用Spring securitySpring 项目。我们通过定义来定义安全过滤器

 <b:bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy">

filter-chain-map

web.xml 我们这样做

<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>

这一切都很好:)。现在,当根据doc 连接Spring sessionredis 时,接下来的几行

<context:annotation-config />
<bean class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration"/>

创建一个名为springSessionRepositoryFilterfilter。所以基本上我们所做的就是在每个自定义filter-chain 中添加该过滤器作为第一个过滤器。即:

<b:bean id="springSecurityFilterChain"   class="org.springframework.security.web.FilterChainProxy">
     <filter-chain-map request-matcher="ant">

           <filter-chain pattern="/api/someapieformobilelogin" filters="none" />  <!-- no filter on login -->
        <filter-chain pattern="/api/**"
            filters="springSessionRepositoryFilter, securityContextFilter,and some other spring security filter />

        <filter-chain pattern="/**"
            filters="springSessionRepositoryFilter, securityContextFilter,and some other spring security filter />

结果:该应用似乎运行良好,并且通过redis-climonitoring 显示spring 正在与redis 通信。

问题

filter-chain 中使用springSessionRepositoryFilter 可以吗?还是我们滥用了过滤系统?

谢谢,

橡木

编辑

似乎上述方法不适用于想要从代码中Authenticate 用户的情况,即

Authentication authentication = authenticationManager
                .authenticate(authenticationToken);
SecurityContext securityContext = SecurityContextHolder
                .getContext();
securityContext.setAuthentication(authentication);

将失败。可能是因为它不足以通过filter-chainorg.springframework.security.web.FilterChainProxy 运行它。

你觉得在web.xml 中以filter 运行它会怎样?

<filter>
    <filter-name>springSessionRepositoryFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

<filter>
    <filter-name>springSecurityFilterChain</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-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

以上将强制在springSecurityFilterChain 之前运行springSessionRepositoryFilter,但在此示例中org.springframework.web.filter.DelegatingFilterProxy 被调用两次。还有其他方法可以让springSessionRepositoryFilterspringSecurityFilterChain 过滤器之前作为过滤器运行吗?

【问题讨论】:

我知道这是一个老问题。 bu 你找到解决这个问题的方法了吗?我目前面临同样的问题 这个确实老问题,我想我可以看看答案。你还需要吗? 您好,谢谢您的回复。我们暂时从项目中删除了 spring-session,因为我们无法解决这个问题。如果花费太多时间,您不必搜索答案 嘿,我添加了对这个问题的回答。希望它可以帮助您解决问题 【参考方案1】:

根据我的测试,springSessionRepositoryFilter 必须先运行。这是因为springSessionRepositoryFilter 替换了HttpSession 实现。这是我使用xml 文件的解决方案。

redis-cache.xml

<context:annotation-config />
<bean
    class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration" />

<bean
    class="org.springframework.security.web.session.HttpSessionEventPublisher" />

<!-- end of seesion managment configuration -->


<bean id="redisConnectionFactory"
    class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
    <property name="port" value="$app.redis.port" />
    <property name="hostName" value="$app.redis.hostname" />
    <property name="password" value="$app.redis.password" />
    <property name="usePool" value="true" />
</bean>

我们使用和 RedisHttpSessionConfiguration 的组合,因为 Spring Session 还没有提供 XML Namespace 支持(参见 gh-104)。这将创建一个名为 springSessionRepositoryFilter 的 Spring Bean,它实现了 Filter。过滤器负责替换 Spring Session 支持的 HttpSession 实现。在这种情况下,Spring Session 由 Redis 支持。 source

现在,由于我们有名为 springSessionRepositoryFiltersession filter,它必须作为第一个过滤器运行,因为它替换了 HttpSession 实现。

为此,我们将其声明为web.xml 中的第一个过滤器。有关过滤器和过滤器订单的更多信息,请查看docs

web.xml

<filter>
    <filter-name>springSessionRepositoryFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>


<filter>
    <filter-name>springSecurityFilterChain</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-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
    /WEB-INF/redis-cache.xml
    </param-value>
</context-param>

 <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

请注意,第一个运行的是springSessionRepositoryFilter。但实际上org.springframework.web.filter.DelegatingFilterProxy 类正在运行,它通过bean 的名称查找过滤器。因此它会搜索我们早期配置创建的 bean。 reference

关于redis-cache.xml 的额外行也很重要。否则我们的springapplication context无法知道我们的redis配置

reference

【讨论】:

感谢您的回答。我现在有一个类似的设置,但我们仍然有一些请求的问题。你认为两个 DelegatingFilterProxy 会不会有问题?【参考方案2】:

没关系。来自Javadoc:

SessionRepositoryFilter 必须放在任何访问 HttpSession 或可能提交响应的过滤器之前,以确保会话被覆盖并正确持久化。

只要在可以提交响应或访问HttpSession 的任何内容之前添加springSessionRepositoryFilter,就可以了。对于 Spring Security,您要确保的主要内容是 springSessionRepositoryFilterSecurityContextPersistenceFilter 之前。这可以通过在容器中或 Spring Security 的 FilterChainProxy(即 &lt;filter-chain&gt;)中包含 springSessionRepositoryFilter 来完成。

【讨论】:

您好,感谢您的回复。上面的解决方案提出了一些问题。例如,尝试从代码中执行 SecurityContext securityContext = SecurityContextHolder.getContext(); securityContext.setAuthentication(authentication); 似乎无法运行。我的想法是,即使这个过滤器通过&lt;filter-chain&gt; 设置为第一个过滤器,它仍然不够,应该在它之前运行。你怎么看?

以上是关于如何使用 Spring Session + Spring security xml 配置和多重安全过滤器的主要内容,如果未能解决你的问题,请参考以下文章

java web 中分布式 session 的实现

spring框架发送ajax检查session是不是过期

从SqlSessionFactoryBean的引用浅谈spring两种bean模式

What is the best way to handle Invalid CSRF token found in the request when session times out in Spr

如何使用Spring Session实现分布式Session管理

如何在 Spring-mvc 中使用 Session 属性