2013-04-11 442 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); 

     } 

    }