如何使用 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 security
的Spring
项目。我们通过定义来定义安全过滤器
<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 session
和redis
时,接下来的几行
<context:annotation-config />
<bean class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration"/>
创建一个名为springSessionRepositoryFilter
的filter
。所以基本上我们所做的就是在每个自定义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-cli
的monitoring
显示spring
正在与redis
通信。
问题
在filter-chain
中使用springSessionRepositoryFilter
可以吗?还是我们滥用了过滤系统?
谢谢,
橡木
编辑
似乎上述方法不适用于想要从代码中Authenticate
用户的情况,即
Authentication authentication = authenticationManager
.authenticate(authenticationToken);
SecurityContext securityContext = SecurityContextHolder
.getContext();
securityContext.setAuthentication(authentication);
将失败。可能是因为它不足以通过filter-chain
或org.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
被调用两次。还有其他方法可以让springSessionRepositoryFilter
在springSecurityFilterChain
过滤器之前作为过滤器运行吗?
【问题讨论】:
我知道这是一个老问题。 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
现在,由于我们有名为 springSessionRepositoryFilter
的 session 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
的额外行也很重要。否则我们的spring
application context
无法知道我们的redis配置
reference
【讨论】:
感谢您的回答。我现在有一个类似的设置,但我们仍然有一些请求的问题。你认为两个 DelegatingFilterProxy 会不会有问题?【参考方案2】:没关系。来自Javadoc:
SessionRepositoryFilter 必须放在任何访问 HttpSession 或可能提交响应的过滤器之前,以确保会话被覆盖并正确持久化。
只要在可以提交响应或访问HttpSession
的任何内容之前添加springSessionRepositoryFilter
,就可以了。对于 Spring Security,您要确保的主要内容是 springSessionRepositoryFilter
在 SecurityContextPersistenceFilter
之前。这可以通过在容器中或 Spring Security 的 FilterChainProxy
(即 <filter-chain>
)中包含 springSessionRepositoryFilter
来完成。
【讨论】:
您好,感谢您的回复。上面的解决方案提出了一些问题。例如,尝试从代码中执行SecurityContext securityContext = SecurityContextHolder.getContext(); securityContext.setAuthentication(authentication);
似乎无法运行。我的想法是,即使这个过滤器通过<filter-chain>
设置为第一个过滤器,它仍然不够,应该在它之前运行。你怎么看?以上是关于如何使用 Spring Session + Spring security xml 配置和多重安全过滤器的主要内容,如果未能解决你的问题,请参考以下文章
从SqlSessionFactoryBean的引用浅谈spring两种bean模式
What is the best way to handle Invalid CSRF token found in the request when session times out in Spr