Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/spring-mvc/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
JavaEE容器(JBoss)中的Spring安全性和会话超时_Spring_Spring Mvc_Spring Security_Jboss7.x_Servlet 3.0 - Fatal编程技术网

JavaEE容器(JBoss)中的Spring安全性和会话超时

JavaEE容器(JBoss)中的Spring安全性和会话超时,spring,spring-mvc,spring-security,jboss7.x,servlet-3.0,Spring,Spring Mvc,Spring Security,Jboss7.x,Servlet 3.0,我有一个要求,那就是在30分钟不活动后,会话将过期 我的堆栈如下所示: JBoss7.2 SpringMVC4.0.6 Spring Security 3.2.4 一些相关信息: 预认证由JBoss(LDAP和SPNEGO)完成 Spring Security用于整个应用程序的授权目的。SessionRegistry工作正常,因为我得到了一个当前HTTP会话列表(CurrentSessionController.java和一个JSP),可以使现有会话过期 首选Java配置 问题是,如果用

我有一个要求,那就是在30分钟不活动后,会话将过期

我的堆栈如下所示:

  • JBoss7.2
  • SpringMVC4.0.6
  • Spring Security 3.2.4
一些相关信息:

  • 预认证由JBoss(LDAP和SPNEGO)完成
  • Spring Security用于整个应用程序的授权目的。SessionRegistry工作正常,因为我得到了一个当前HTTP会话列表(CurrentSessionController.java和一个JSP),可以使现有会话过期
  • 首选Java配置
问题是,如果用户闲置一段时间,然后达到web.xml中定义的会话超时阈值,他仍然可以浏览应用程序。创建了一个新的HttpSession,他仍然可以使用该应用程序

我想要的是,一旦会话过期,用户就不能调用另一个请求处理程序(理想情况下,Spring Security会像使用sessionInformation.expireNow()时一样使会话过期)。用户的下一个操作(HTTP请求)将重定向到特定的JSP页面

web.xml(1分钟用于测试)

}

我还使用了Spring会话范围的目标bean(会话对象模式),定义如下:

SessionObject.java

@Override
    public void onStartup(ServletContext servletContext) throws ServletException {

        WebApplicationContext applicationContext = this.getContext();

        this.setServletFilters(servletContext);
        this.setServletListeners(servletContext, applicationContext);

        ServletRegistration.Dynamic dispatcherServlet = servletContext.addServlet("dispatcherServlet", new DispatcherServlet(applicationContext));
        dispatcherServlet.setLoadOnStartup(1);
        dispatcherServlet.addMapping("/rest/*");
    }

    private AnnotationConfigWebApplicationContext getContext() {

        AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
        context.scan("my.app.spring4base.config");

        return context;
    }

    private void setServletFilters(ServletContext servletContext) {

        FilterRegistration.Dynamic springSecurityFilterChain = servletContext.addFilter("springSecurityFilterChain", new DelegatingFilterProxy("springSecurityFilterChain"));
        springSecurityFilterChain.addMappingForUrlPatterns(null, false, "/rest/*");

        FilterRegistration.Dynamic sessionFilter = servletContext.addFilter("sessionFilter", SessionFilter.class);
        sessionFilter.addMappingForUrlPatterns(null, false, "/rest/*");

        FilterRegistration.Dynamic requestContextFilter = servletContext.addFilter("requestContextFilter", RequestContextFilter.class);
        requestContextFilter.addMappingForUrlPatterns(null, false, "/*");

        FilterRegistration.Dynamic encodingFilter = servletContext.addFilter("encodingFilter", CharacterEncodingFilter.class);
        encodingFilter.addMappingForUrlPatterns(null, false, "/*");

        encodingFilter.setInitParameters(new HashMap<String, String>() {{
            put("encoding", StandardCharsets.UTF_8.name());
            put("forceEncoding", "true");
        }});
    }

    private void setServletListeners(ServletContext servletContext, WebApplicationContext applicationContext) {
        servletContext.addListener(new ContextLoaderListener(applicationContext));
        servletContext.addListener(new RequestContextListener());
        servletContext.addListener(new SpringApplicationScopedBeanDeprefixer());
        servletContext.addListener(new SpringSessionScopedBeanDeprefixer());
        servletContext.addListener(new HttpSessionEventPublisher());
    }
@Configuration
@EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Bean
public CustomPreAuthenticationFilter customPreAuthenticationFilter() {
    return new CustomPreAuthenticationFilter();
}

@Bean
public SessionRegistry sessionRegistry() {
    return new SessionRegistryImpl();
}

@Override
protected void configure(HttpSecurity http) throws Exception {

    http

        .addFilterAfter(this.customPreAuthenticationFilter(), J2eePreAuthenticatedProcessingFilter.class)

        .csrf().disable()

        .logout()
            .logoutUrl("/rest/logout")
            .logoutSuccessUrl("/static/jsp/logout.jsp")
            .invalidateHttpSession(true)
            .deleteCookies("JSESSIONID")
            .permitAll()

        .and()

            .authorizeRequests()
            .antMatchers("/login","/accessDenied", "/sessionTimeout", "/resources/**", "/static/**").permitAll()
            .antMatchers("/security/*").hasRole("ADMIN")
            .antMatchers("/rest/**").authenticated()
            .antMatchers("/rest/**").hasRole("USER")
            .and().anonymous().disable()

         .jee()
            .mappableRoles("USER","ADMIN", "DEVELOPER")

         .and()
            .sessionManagement()
                .maximumSessions(1)
                .sessionRegistry(sessionRegistry())
                .maxSessionsPreventsLogin(true)
                .expiredUrl("/static/jsp/sessionTimeout.jsp")

            .and()
                .invalidSessionUrl("/static/jsp/sessionInvalid.jsp")
                .sessionFixation();
}
@Component
@Scope( 
    value = "session", 
    proxyMode = ScopedProxyMode.TARGET_CLASS
)
public class SessionObject {

    private User currentUser;

    public SessionObject() {
    }

    public User getCurrentUser() {
        return currentUser;
    }

    public void setCurrentUser(User user) {
        this.currentUser = user;
    }

    public boolean isConnected() {
        return currentUser != null; 
    }
}
 public class SessionFilter implements Filter {

        public void destroy() {
        }

        @Override
        public void init(FilterConfig arg0) throws ServletException {
        }

    public void doFilter(ServletRequest req, ServletResponse res,
            FilterChain chain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;

        HttpSession session = request.getSession(false);

        //Also tried the following:
        //if (sessionObject == null) {
        if (session.getAttribute("scopedTarget.sessionObject") == null) {
            response.sendRedirect("/static/jsp/sessionTimeout.jsp");
        } else {
            chain.doFilter(request, response);
        }
    }
}
我尝试使用Servlet过滤器,然后检查我的Spring会话范围bean是否存在,但结果证明它总是可用的

SessionFilter.java

@Override
    public void onStartup(ServletContext servletContext) throws ServletException {

        WebApplicationContext applicationContext = this.getContext();

        this.setServletFilters(servletContext);
        this.setServletListeners(servletContext, applicationContext);

        ServletRegistration.Dynamic dispatcherServlet = servletContext.addServlet("dispatcherServlet", new DispatcherServlet(applicationContext));
        dispatcherServlet.setLoadOnStartup(1);
        dispatcherServlet.addMapping("/rest/*");
    }

    private AnnotationConfigWebApplicationContext getContext() {

        AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
        context.scan("my.app.spring4base.config");

        return context;
    }

    private void setServletFilters(ServletContext servletContext) {

        FilterRegistration.Dynamic springSecurityFilterChain = servletContext.addFilter("springSecurityFilterChain", new DelegatingFilterProxy("springSecurityFilterChain"));
        springSecurityFilterChain.addMappingForUrlPatterns(null, false, "/rest/*");

        FilterRegistration.Dynamic sessionFilter = servletContext.addFilter("sessionFilter", SessionFilter.class);
        sessionFilter.addMappingForUrlPatterns(null, false, "/rest/*");

        FilterRegistration.Dynamic requestContextFilter = servletContext.addFilter("requestContextFilter", RequestContextFilter.class);
        requestContextFilter.addMappingForUrlPatterns(null, false, "/*");

        FilterRegistration.Dynamic encodingFilter = servletContext.addFilter("encodingFilter", CharacterEncodingFilter.class);
        encodingFilter.addMappingForUrlPatterns(null, false, "/*");

        encodingFilter.setInitParameters(new HashMap<String, String>() {{
            put("encoding", StandardCharsets.UTF_8.name());
            put("forceEncoding", "true");
        }});
    }

    private void setServletListeners(ServletContext servletContext, WebApplicationContext applicationContext) {
        servletContext.addListener(new ContextLoaderListener(applicationContext));
        servletContext.addListener(new RequestContextListener());
        servletContext.addListener(new SpringApplicationScopedBeanDeprefixer());
        servletContext.addListener(new SpringSessionScopedBeanDeprefixer());
        servletContext.addListener(new HttpSessionEventPublisher());
    }
@Configuration
@EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Bean
public CustomPreAuthenticationFilter customPreAuthenticationFilter() {
    return new CustomPreAuthenticationFilter();
}

@Bean
public SessionRegistry sessionRegistry() {
    return new SessionRegistryImpl();
}

@Override
protected void configure(HttpSecurity http) throws Exception {

    http

        .addFilterAfter(this.customPreAuthenticationFilter(), J2eePreAuthenticatedProcessingFilter.class)

        .csrf().disable()

        .logout()
            .logoutUrl("/rest/logout")
            .logoutSuccessUrl("/static/jsp/logout.jsp")
            .invalidateHttpSession(true)
            .deleteCookies("JSESSIONID")
            .permitAll()

        .and()

            .authorizeRequests()
            .antMatchers("/login","/accessDenied", "/sessionTimeout", "/resources/**", "/static/**").permitAll()
            .antMatchers("/security/*").hasRole("ADMIN")
            .antMatchers("/rest/**").authenticated()
            .antMatchers("/rest/**").hasRole("USER")
            .and().anonymous().disable()

         .jee()
            .mappableRoles("USER","ADMIN", "DEVELOPER")

         .and()
            .sessionManagement()
                .maximumSessions(1)
                .sessionRegistry(sessionRegistry())
                .maxSessionsPreventsLogin(true)
                .expiredUrl("/static/jsp/sessionTimeout.jsp")

            .and()
                .invalidSessionUrl("/static/jsp/sessionInvalid.jsp")
                .sessionFixation();
}
@Component
@Scope( 
    value = "session", 
    proxyMode = ScopedProxyMode.TARGET_CLASS
)
public class SessionObject {

    private User currentUser;

    public SessionObject() {
    }

    public User getCurrentUser() {
        return currentUser;
    }

    public void setCurrentUser(User user) {
        this.currentUser = user;
    }

    public boolean isConnected() {
        return currentUser != null; 
    }
}
 public class SessionFilter implements Filter {

        public void destroy() {
        }

        @Override
        public void init(FilterConfig arg0) throws ServletException {
        }

    public void doFilter(ServletRequest req, ServletResponse res,
            FilterChain chain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;

        HttpSession session = request.getSession(false);

        //Also tried the following:
        //if (sessionObject == null) {
        if (session.getAttribute("scopedTarget.sessionObject") == null) {
            response.sendRedirect("/static/jsp/sessionTimeout.jsp");
        } else {
            chain.doFilter(request, response);
        }
    }
}
会话超时时从Spring Security记录日志

2015-09-17 08:32:56,586 DEBUG [org.springframework.security.web.session.HttpSessionEventPublisher] (http-/0.0.0.0:8080-2) Publishing event: org.springframework.security.web.session.HttpSessionDestroyedEvent[source=org.apache.catalina.session.StandardSessionFacade@61da4a]
2015-09-17 08:32:56,586 DEBUG [org.springframework.security.core.session.SessionRegistryImpl] (http-/0.0.0.0:8080-2) Removing session DnfCin+LXESn6QvKqd6jOlPe from principal's set of registered sessions
2015-09-17 08:32:56,586 DEBUG [org.springframework.security.core.session.SessionRegistryImpl] (http-/0.0.0.0:8080-2) Removing principal org.springframework.security.core.userdetails.User@4eb878aa: Username: MYUSERID@MY.DOMAIN; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_ADMIN,ROLE_DEVELOPER,ROLE_USER from registry
  • 超时前的会话ID为:DnfCin+LXESn6QvKqd6jOlPe
  • 超时(刷新)后的会话ID为:dcW8VDH7uBjmd9Ve4v4PoFHZ
会话超时时

2015-09-17 08:32:56,586 DEBUG [org.springframework.security.web.session.HttpSessionEventPublisher] (http-/0.0.0.0:8080-2) Publishing event: org.springframework.security.web.session.HttpSessionDestroyedEvent[source=org.apache.catalina.session.StandardSessionFacade@61da4a]
2015-09-17 08:32:56,586 DEBUG [org.springframework.security.core.session.SessionRegistryImpl] (http-/0.0.0.0:8080-2) Removing session DnfCin+LXESn6QvKqd6jOlPe from principal's set of registered sessions
2015-09-17 08:32:56,586 DEBUG [org.springframework.security.core.session.SessionRegistryImpl] (http-/0.0.0.0:8080-2) Removing principal org.springframework.security.core.userdetails.User@4eb878aa: Username: MYUSERID@MY.DOMAIN; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_ADMIN,ROLE_DEVELOPER,ROLE_USER from registry
会话超时后(创建新会话时)

任何帮助都将不胜感激


谢谢你

将上述评论转换为一条建议


由于J2eePreAuthenticatedProcessingFilter正在重新验证用户并填充主体,会话固定或会话筛选器认为没有发生会话失效,因为存在新主体并盲目创建新会话。因此,您可以尝试在会话失效时将用户更新为已过期,并在预身份验证时检查用户是否已过期,是否不再允许进行身份验证…(例如,即使在会话超时后有记住cookie的情况下,也可以使用持久登录想法重新身份验证)

以上注释转换为一个建议


由于J2eePreAuthenticatedProcessingFilter正在重新验证用户并填充主体,会话固定或会话筛选器认为没有发生会话失效,因为存在新主体并盲目创建新会话。因此,您可以尝试在会话失效时将用户更新为已过期,并在预身份验证时检查用户是否已过期,是否不再允许进行身份验证…(例如,即使在会话超时后有RememberCookie,也可以使用persistent_login idea重新身份验证)

我想说,问题是因为您使用的是
CustomPreAuthenticationFilter
,可能是
J2EEPreAuthenticationdProcessingFilter
,因为这基本上会重新验证用户(我怀疑)。签入
SessionFilter
将失败,尤其是在您的情况下,因为它是在Spring安全过滤器之后定义的(因此它将出现)。无法从其他线程/请求中终止
HttpSession
,因为这基本上是一种安全违规行为(如果有人可以访问您的会话状态,您会有什么感觉!)。请尝试将org.springframework.security设置为调试级日志记录-Spring security通常有很好的日志记录,并且您怀疑的事件(会话无效和重新创建)很有可能出现在日志中。@Shailendra:我已将日志添加到问题中。非常感谢。不确定您的
CustomPreAuthenticationFilter
做了什么,但可能您想让它更智能一点(或者实际上是
J2EEPreAuthenticationdProcessingFilter
)当检测到无效会话时,您可以更明智地不进行身份验证,但不确定在这种情况下会出现什么中断。因为J2eePreAuthenticatedProcessingFilter正在重新验证用户并填充主体,而会话固定或会话筛选器认为没有发生会话无效,因为存在新的主体和盲目地创建新会话。因此,您可以尝试在会话失效时将用户更新为已过期,并在预身份验证时检查用户是否已过期,是否不再允许进行身份验证…(例如,即使在会话超时后有RememberCookie,也可以使用persistent_login idea重新身份验证)我想说的是,问题来自这样一个事实:您使用的是
CustomPreAuthenticationFilter
,可能是
J2EEPreAuthenticationdProcessingFilter
,因为这基本上会重新验证用户(我怀疑)。签入
SessionFilter
将失败,尤其是在您的情况下,因为它是在Spring安全过滤器之后定义的(因此它将出现)。无法从其他线程/请求中终止
HttpSession
,因为这基本上是一种安全违规行为(如果有人可以访问您的会话状态,您会有什么感觉!)。请尝试将org.springframework.security设置为调试级日志记录-Spring security通常有很好的日志记录,并且您怀疑的事件(会话无效和重新创建)很有可能出现在日志中。@Shailendra:我已将日志添加到问题中。非常感谢。不确定您的
CustomPreAuthenticationFilter
做了什么,但可能您想让它更智能一点(或者实际上是
J2EEPreAuthenticationdProcessingFilter
),您可以让它更智能一点,在