如燕盘旋而来的思念 2018-03-27 08:22 采纳率: 0%
浏览 2515
已结题

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

项目中已经在使用了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?

  • 写回答

3条回答 默认 最新

  • 关注

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

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

    先贴出来我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中处理。

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

    评论

报告相同问题?

悬赏问题

  • ¥100 c语言,请帮蒟蒻看一个题
  • ¥15 名为“Product”的列已属于此 DataTable
  • ¥15 安卓adb backup备份应用数据失败
  • ¥15 eclipse运行项目时遇到的问题
  • ¥15 关于#c##的问题:最近需要用CAT工具Trados进行一些开发
  • ¥15 南大pa1 小游戏没有界面,并且报了如下错误,尝试过换显卡驱动,但是好像不行
  • ¥15 没有证书,nginx怎么反向代理到只能接受https的公网网站
  • ¥50 成都蓉城足球俱乐部小程序抢票
  • ¥15 yolov7训练自己的数据集
  • ¥15 esp8266与51单片机连接问题(标签-单片机|关键词-串口)(相关搜索:51单片机|单片机|测试代码)