2013-04-11 206 views
5

我需要在用户注销时删除cookie JSESSIONID。要做到这一点我已经添加下面的配置到我的安全配置:SpringSecurity:无法删除JSESSIONID

<http> 
    <form-login login-page="/login*" authentication-failure-url="/login?try_again" /> 
    <http-basic /> 
    <logout logout-url="/logout" delete-cookies="JSESSIONID" /> 
    <session-management invalid-session-url="/timeout" /> 

    <intercept-url pattern="/login*" access="IS_AUTHENTICATED_ANONYMOUSLY" /> 

    ... 

</http> 

但是,而不是被删除,cookie将被刚刚成为复制:

Old cookie

New cookie

所以一直将浏览器重定向到“/ timeout”URL。

我试图追查这是怎么回事使用Chrome网络浏览器的开发者工具,我发现,这个cookie建立与此响应头:

Set-Cookie:JSESSIONID=CFF85EA743724F23FDA0317A75CFAD44; Path=/website/; HttpOnly 

而与此响应头删除:

Set-Cookie:JSESSIONID=""; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/website 

我不确定,但它似乎是这些标题的“路径”字段中的原因:第一个指向“/ website /”,第二个指向“ /网站”。

难道是所描述麻烦的原因吗?如果不是原因(或不是唯一原因),那么其他原因是什么?我应该如何解决这个问题?

+0

见http://static.springsource.org/spring-security/site/docs/3.2.x/reference/springsecurity-single.html#ns-session- mgmt(第3.3.3节)...不幸的是,这不能保证与每个servlet容器一起工作,所以你需要在你的环境中测试它。另请参阅相关的脚注。 – Ritesh 2013-04-11 12:47:12

回答

6

您不需要像这样明确删除JSESSIONID cookie。它不是由Spring Security管理的,而是由你的servlet容器管理的。 Spring Security默认会在注销时使http会话无效,这会导致您的servlet容器删除JSESSIONID cookie。

+2

http://docs.spring.io/spring-security/site/docs/3.1.x/reference/springsecurity-single.html#ns-session-mgmt表明,如果您重新使用会话管理标签,您可能需要明确删除该cookie。 – Richie 2014-01-28 21:54:03

2

这是我的无效会议:

<security:logout invalidate-session="true" logout-success-url="/myapp/auth/login" logout-url="/myapp/auth/logout" /> 
1

如何删除注销很简单: 您实现注销,并把这些代码的方法:

HttpSession session = request.getSession(false); 
    if (session != null) { 
     session.invalidate(); 
    } 

无效的会话将使cookie无效。

但我试过并发现,当我关闭浏览器而没有注销时,JSESSIONID cookie仍然存在,并且用户可以在打开浏览器时进入系统。

为了消除这种情况,我创建了一个筛选器,它也会在登录时使会话无效,从而创建一个新的会话,您将从头开始执行登录。

@WebFilter(urlPatterns = {"/login/*"}, description = "sessionKiller", filterName="sessionKiller") 
public class SessionKillerFilter implements Filter{ 

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

    @Override 
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { 
     //kill older session and create new one on explicit login 
     //this is to prevent user to login 2-ce 
     //also this is prevention of re-connect on cookie base, when browser closed and then open 
     HttpServletRequest request = (HttpServletRequest)req; 
     HttpSession session = request.getSession(false); 
     if(session!=null){ 
      session.invalidate();//old session invalidated 
     } 
     request.getSession(true);//new session created 

     chain.doFilter(req, resp); 
    } 

    @Override 
    public void destroy() {} 
} 
3

在我的情况下,即使SecurityContextLogoutHandler电话session.invalidate()JSESSIONID不会被清除一些原因。它的价值保持不变。

我尝试使用delete-cookies="JSESSIONID"与OP试用相同的方式,我相信我有同样的问题:为Cookie设置的路径是上下文路径没有/,所以它仍然不会被清除(这是命令删除一个不存在的cookie)。

我结束了写我自己的ProperCookieClearLogoutHandler,这是同文以CookieClearLogoutHandler除外设置Cookie的上下文路径线:

package com.testdomain.testpackage; 

import java.util.Arrays; 
import java.util.List; 

import javax.servlet.http.Cookie; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 

import org.springframework.security.core.Authentication; 
import org.springframework.security.web.authentication.logout.LogoutHandler; 
import org.springframework.util.Assert; 
import org.springframework.util.StringUtils; 

public final class ProperCookieClearingLogoutHandler implements LogoutHandler { 
    private final List<String> cookiesToClear; 

    public ProperCookieClearingLogoutHandler(String... cookiesToClear) { 
     Assert.notNull(cookiesToClear, "List of cookies cannot be null"); 
     this.cookiesToClear = Arrays.asList(cookiesToClear); 
    } 

    public void logout(HttpServletRequest request, HttpServletResponse response, 
      Authentication authentication) { 
     for (String cookieName : cookiesToClear) { 
      Cookie cookie = new Cookie(cookieName, null); 
      String cookiePath = request.getContextPath() + "/"; 
      if (!StringUtils.hasLength(cookiePath)) { 
       cookiePath = "/"; 
      } 
      cookie.setPath(cookiePath); 
      cookie.setMaxAge(0); 
      response.addCookie(cookie); 
     } 
    } 
} 

然后,我设置了LogoutFilterspring-security.xml这样的配置;

<bean id="logoutFilter" 
     class="org.springframework.security.web.authentication.logout.LogoutFilter"> 
     <constructor-arg name="logoutSuccessUrl" value="/views/login/login.xhtml?logout" /> 
     <constructor-arg> 
      <list> 
       <bean id="properCookieClearingLogoutHandler" 
        class="com.imatia.arpad.gplenos.authorization.ProperCookieClearingLogoutHandler"> 
        <constructor-arg name="cookiesToClear"> 
         <list> 
          <value>JSESSIONID</value> 
         </list> 
        </constructor-arg> 
       </bean> 
       <bean id="securityContextLogoutHandler" 
        class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"> 
       </bean> 
      </list> 
     </constructor-arg> 
     <property name="filterProcessesUrl" value="/logout" /> 
    </bean> 
0

由于cookie路径的不同,Spring提供的默认CookieClearingLogoutHandler无法清除JSESSIONID。

你不应该改变cookie的路径。这会改变cookie的身份。如果cookie设置为/ foo之类的路径,并将其更改为/,则客户端不会将更改的cookie与原始cookie关联。 Cookie由名称和路径标识。

因此需要实现自定义CookieClearingLogoutHandler作为在上述溶液中,即(ProperCookieClearingLogoutHandler.class)中所示,并将其设置到弹簧安全如示于下面的代码。相反使用.deleteCookies的(“JSESSIONID”,“用户”)它默认添加了CookieClearingLogoutHandler。

春季安全的Java配置:

@Configuration 
@EnableWebSecurity 
@ComponentScan(basePackages = "com.dentist.webapp") 
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter { 

    @Autowired 
    private SessionRegistry sessionRegistry; 

    @Override 
    protected void configure(HttpSecurity http) throws Exception { 
     http.authorizeRequests().antMatchers("/resources/**", "/signup/*", "/about", "/login/*").permitAll().anyRequest() 
       .authenticated() 
       .and().formLogin() 
           .loginPage("/login/form") 
           .permitAll() 
       .and().logout() 
           .invalidateHttpSession(true) 
           .clearAuthentication(true) 
          // .deleteCookies("JSESSIONID","USER") 
           .addLogoutHandler(new ProperCookieClearingLogoutHandler("JSESSIONID","USER")) 
           .permitAll() 
       .and().sessionManagement() 
           .maximumSessions(1) 
           .maxSessionsPreventsLogin(true) 
           .expiredUrl("/accessDenied") 
           .sessionRegistry(sessionRegistry); 

     } 

    }