我需要在用户注销时删除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” ”
这是所描述的麻烦的原因吗?如果不是原因(或不是唯一原因),那么其他原因是什么?我该如何解决这个问题?
答案 0 :(得分:6)
您无需像这样明确删除JSESSIONID
Cookie。它不是由Spring Security管理的,而是由您的servlet容器管理的。默认情况下,Spring Security会在注销时使http会话无效,这会导致您的servlet容器删除JSESSIONID
cookie。
答案 1 :(得分:3)
在我的情况下出于某种原因,即使SecurityContextLogoutHandler来电session.invalidate() JSESSIONID
也不会被清除。它的价值保持不变。
我尝试以与OP尝试相同的方式使用delete-cookies="JSESSIONID"
,我相信我遇到了同样的问题:为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);
}
}
}
然后我以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>
答案 2 :(得分:2)
这就是我使会话无效的方式:
<security:logout invalidate-session="true" logout-success-url="/myapp/auth/login" logout-url="/myapp/auth/logout" />
答案 3 :(得分:1)
由于cookie路径不同,spring提供的默认CookieClearingLogoutHandler无法清除JSESSIONID。
您不应该更改cookie的路径。这会改变cookie身份。如果为/ foo这样的路径设置了cookie并将其更改为/,则客户端不再将更改后的cookie与原始cookie相关联。 Cookie由名称和路径标识。
因此,你需要实现一个自定义CookieClearingLogoutHandler,如上面的解决方案所示,即(ProperCookieClearingLogoutHandler.class)并将其设置为spring security,如下面的代码所示。而不是使用.deleteCookies(&#34; JSESSIONID&#34;, &#34; USER&#34;)默认添加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);
}
}
答案 4 :(得分:0)
如何在注销时删除很简单: 实现注销并将该代码放在方法中:
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() {}
}