Spring Security:无法删除 JSESSIONID
Posted
技术标签:
【中文标题】Spring Security:无法删除 JSESSIONID【英文标题】:SpringSecurity: Fail to delete JSESSIONID 【发布时间】:2013-04-03 11:48:01 【问题描述】:我需要在用户注销时删除 cookie 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 并没有被删除,而是被复制了:
所以它不断将浏览器重定向到“/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/”,而在第二个中它指向“/website ”。
是所描述的问题的原因吗?如果这不是原因(或不是唯一原因),那么其他原因是什么?我该如何解决这个问题?
【问题讨论】:
参见static.springsource.org/spring-security/site/docs/3.2.x/…(第 3.3.3 节)...不幸的是,这不能保证适用于每个 servlet 容器,因此您需要在您的环境中对其进行测试。另见相关脚注。 ducmanhphan.github.io/2019-02-22-Logout-in-Spring-Boot 【参考方案1】:您不需要像这样显式删除JSESSIONID
cookie。它不是由 Spring Security 管理的,而是由您的 servlet 容器管理的。 Spring Security 将默认在注销时使 http 会话无效,这反过来会导致您的 servlet 容器删除 JSESSIONID
cookie。
【讨论】:
docs.spring.io/spring-security/site/docs/3.1.x/reference/… 表明,如果您使用会话管理标签,您可能需要明确删除 cookie。 ducmanhphan.github.io/2019-02-22-Logout-in-Spring-Boot这篇精彩的文章会有所帮助!【参考方案2】:在我的情况下,即使 SecurityContextLogoutHandler 调用 session.invalidate() JSESSIONID
不会被清除。它的值保持不变。
我尝试以与 OP 相同的方式使用 delete-cookies="JSESSIONID"
,并且我相信我遇到了同样的问题:为 cookie 设置的路径是最后没有 /
的上下文路径,所以它仍然不会t 被清除(这是命令删除一个不存在的 cookie)。
我最终编写了自己的 ProperCookieClearLogoutHandler
,它与 CookieClearingLogoutHandler 相同,除了设置 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);
然后我以这种方式在spring-security.xml
上设置LogoutFilter 的配置;
<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>
【讨论】:
我认为String cookiePath = request.getContextPath() + "/"; if (!StringUtils.hasLength(cookiePath)) cookiePath = "/";
有问题,如果路径已经有/
,例如如果它是根。也许更好String cookiePath = request.getContextPath(); if (!cookiePath.endsWith("/")) cookiePath += "/";
当用户使用记住我选项登录时,我也在努力注销用户。在 /logout 上,我编写了一个显式删除和过期 cookie 的方法,这对我来说非常有效。谢谢。【参考方案3】:
这就是我使会话无效的方式:
<security:logout invalidate-session="true" logout-success-url="/myapp/auth/login" logout-url="/myapp/auth/logout" />
【讨论】:
【参考方案4】:spring提供的默认CookieClearingLogoutHandler由于cookie路径不同,无法清除JSESSIONID。
您不应更改 cookie 的路径。这将改变 cookie 的身份。如果 cookie 设置为 /foo 之类的路径,并且您将其更改为 /,则客户端将不再将更改后的 cookie 与原始 cookie 关联。 cookie 由名称和路径标识。
因此,您需要实现一个自定义 CookieClearingLogoutHandler,如上述解决方案所示,即 (ProperCookieClearingLogoutHandler.class) 并将其设置为 spring security,如下面的代码所示。而不是使用 .deleteCookies("JSESSIONID","USER")默认添加 CookieClearingLogoutHandler。
Spring Security 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);
【讨论】:
很好解释的答案。也许您可以询问@NotGaeL 并将其代码复制到您的答案中,以便它自己完成。并且不要将其称为“上方”,您永远不知道它会出现在哪里,请使用作者姓名的链接。【参考方案5】:如何在注销时删除很简单: 您实现注销并将该代码放入方法中:
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()
【讨论】:
以上是关于Spring Security:无法删除 JSESSIONID的主要内容,如果未能解决你的问题,请参考以下文章
即使凭据正确,Spring-security 也不会登录用户