spring-session和security同时配置时,session不对该如何解决? 5C

项目中已经在使用了security,在web.xml配置如下

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

近期想要增加spingSession,按照网上说明添加了一个filter

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

两个filter同时配置后,spring-session是生效的,但是security中拿到的session不是同一个,改变filter顺序也没用。我认为不能这样配置两个filter,但是filter-name好像spring要求必须按照规范来写,所以没法把两个filter合并。那么该如何让spring-session和security并存,并且保证security拿到的是同一个session?

2个回答

自己来解答一下这个问题吧:

经过几天的研究,终于搞清楚问题所在:

先贴出来我web.xml的主要配置,用于引入spring-session,spring-security,RequestContextListener


springSessionRepositoryFilter
org.springframework.web.filter.DelegatingFilterProxy


springSecurityFilterChain
org.springframework.web.filter.DelegatingFilterProxy



org.springframework.web.context.request.RequestContextListener

原始现象是:通过以上配置,实现了基于spring-session的集群管理所有session(redis session的配置省略不贴),这时在正常访问某个url时,在controller中,从RequestContextHolder(springmvc提供)可以获取正确的session,也就是被spring-session包装过的session。但是在点击登录时,在security的自定义filter中从RequestContextHolder拿到的是原始的ServletRequest。进一步debug代码发现,登录的url(/account/auth)是经过security的配置的,被spring-security拦截了,这个拦截是由一个security拦截链上插入的一个自定义的Filter>>>>MyprojectLoginFilter所拦截,因为这时请求还未走进DispatcherServlet父类的FrameworkServlet的processRequest,所以RequestContextHolder中的request没有被包装成spring-session的request。那么这时的RequestContextHolder的request是哪里来的呢
?其实是在RequestContextListener接收到的,这个listener的代码如下

public void requestInitialized(ServletRequestEvent requestEvent) {
if (!(requestEvent.getServletRequest() instanceof HttpServletRequest)) {
throw new IllegalArgumentException((new StringBuilder())
.append("Request is not an HttpServletRequest: ")
.append(requestEvent.getServletRequest()).toString());
} else {
HttpServletRequest request = (HttpServletRequest) requestEvent
.getServletRequest();
ServletRequestAttributes attributes = new ServletRequestAttributes(
request);
request.setAttribute(REQUEST_ATTRIBUTES_ATTRIBUTE, attributes);
LocaleContextHolder.setLocale(request.getLocale());
RequestContextHolder.setRequestAttributes(attributes);
return;
}
}
可以看到监听在接收到requestEvent

后,new了一个ServletRequestAttributes并set到RequestContextHolder中。在没有到达springmvc的DispatcherServlet前,RequestContextHolder中都是原始的HttpServletRequest,而自定义的security的filter是在DispatcherServlet之前执行的,所以filter获得的request是原始的。知道这样的原因后就知道怎么改造了,我暂时这样做:web.xml中security的filter自己来实现,在super.invokeDelegate之前先判断RequestContextHolder的request是不是包装后的session,不是的话自己set进去


springSecurityFilterChain
com.myproject.common.dispatcher.SecurityDelegatingFilterProxy

public class SecurityDelegatingFilterProxy extends DelegatingFilterProxy {

/*
 * (non-Javadoc)
 * 
 * @see
 * org.springframework.web.filter.DelegatingFilterProxy#invokeDelegate(javax
 * .servlet.Filter, javax.servlet.ServletRequest,
 * javax.servlet.ServletResponse, javax.servlet.FilterChain)
 */
@Override
protected void invokeDelegate(Filter delegate, ServletRequest request,
        ServletResponse response, FilterChain filterChain)
        throws ServletException, IOException {
    if (request instanceof HttpServletRequest
            && response instanceof HttpServletResponse) {
        HttpServletRequest contextHolderRequest = ((ServletRequestAttributes) RequestContextHolder
                .getRequestAttributes()).getRequest();
        if (request != contextHolderRequest) {
            RequestContextHolder.setRequestAttributes(
                    new ServletRequestAttributes(
                            (HttpServletRequest) request,
                            (HttpServletResponse) response), true);
        }

    }
    super.invokeDelegate(delegate, request, response, filterChain);

}

}
为什么不在spring-session的filter中进行替换?因为这个filter中拿到的始终是原始request,只有经过它doFilter后,reqeust才是包装后的。所以没法在这个filter中处理。

以上就是整个问题的分析,请大家指正。

Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问
相关内容推荐