注销会在浏览器上留下 JSESSIONID。如何清除它?
Posted
技术标签:
【中文标题】注销会在浏览器上留下 JSESSIONID。如何清除它?【英文标题】:Logout leaves behind JSESSIONID on the browser. How to clear it? 【发布时间】:2013-08-07 01:14:14 【问题描述】:我正在使用以下代码将用户从我的系统中注销。
/**
* This function helps to set the session attribute for the present user to null and then
* removes the attribute itself and this helps in clearing the session
* @param request
* @param response
*/
@RequestMapping(value = AuthConstants.EXIT, method = RequestMethod.POST)
public void exitPrime(HttpServletRequest request, HttpServletResponse response)
/*Getting session and then invalidating it*/
HttpSession session = request.getSession(false);
if(request.isRequestedSessionIdValid() && session != null)
session.invalidate();
这将导致成功注销,但登录时给出的 JSESSION ID 仍保留在浏览器中,因此对于任何新用户,在登录时再次使用相同的 JSESSION ID。我希望 JSESSIONID cookie 仅对当前会话有效,一旦用户注销,它应该被销毁或对下次登录无效。我的登录代码如下:-
/**
* This method allows one to log into the system and generates a token for a valid employee.
* @param authRequest
* @param request
* @param response
* @return
*/
@RequestMapping(value = AuthConstants.ENTRY, method = RequestMethod.POST, consumes = ApplicationConstants.APPLICATION_JSON)
public @ResponseBody
AuthResponse primeEntry(@RequestBody AuthRequest authRequest,HttpServletRequest request, HttpServletResponse response)
AuthResponse authResponse = new AuthResponse();
if(authRequest != null && authRequest.getEmployeeAuth().getEmployeeNumber() != null
&& !authRequest.getEmployeeAuth().getEmployeeNumber().isEmpty())
/*To check whether the user is valid*/
String employeeNumber = authRequest.getEmployeeAuth().getEmployeeNumber();
UserBean userBean = new UserBean();
userBean = userService.getUser(employeeNumber);
if(userBean != null)
HttpSession session = request.getSession(true);
session.setAttribute("user", userBean);
setAuthResponseSuccess(authResponse);
else
/*If user does not exist the too throw error 500*/
setAuthResponseFailure(authResponse);
else
/*If input JSON is not valid then throw error 500*/
setAuthResponseFailure(authResponse);
return authResponse;
我正在使用 Spring 3.2 并且想要手动登录和注销。请帮忙。
完整的类代码
@Controller
@RequestMapping(value = "/auth")
public class AuthController
@Autowired
HttpServletRequest request;
@Autowired
HttpSession session;
@Autowired
IUserService userService;
/**
* This method allows one to log into the system and generates a token for a valid employee.
* @param authRequest
* @param request
* @param response
* @return
*/
@RequestMapping(value = AuthConstants.ENTRY, method = RequestMethod.POST, consumes = ApplicationConstants.APPLICATION_JSON)
public @ResponseBody
AuthResponse primeEntry(@RequestBody AuthRequest authRequest,HttpServletRequest request, HttpServletResponse response)
AuthResponse authResponse = new AuthResponse();
if(authRequest != null && authRequest.getEmployeeAuth().getEmployeeNumber() != null
&& !authRequest.getEmployeeAuth().getEmployeeNumber().isEmpty())
/*To check whether the user is valid*/
String employeeNumber = authRequest.getEmployeeAuth().getEmployeeNumber();
UserBean userBean = new UserBean();
userBean = userService.getUser(employeeNumber);
if(userBean != null)
HttpSession session = request.getSession(true);
session.setAttribute("user", userBean);
setAuthResponseSuccess(authResponse);
else
/*If user does not exist the too throw error 500*/
setAuthResponseFailure(authResponse);
else
/*If input JSON is not valid then throw error 500*/
setAuthResponseFailure(authResponse);
return authResponse;
/**
* This function helps to set the session attribute for the present user to null and then
* removes the attribute itself and this helps in clearing the session
* @param request
* @param response
*/
@RequestMapping(value = AuthConstants.EXIT, method = RequestMethod.POST)
public void exitPrime(HttpServletRequest request, HttpServletResponse response)
/*Getting session and then invalidating it*/
HttpSession session = request.getSession(false);
if(request.isRequestedSessionIdValid() && session != null)
session.invalidate();
private AuthResponse setAuthResponseFailure(AuthResponse authResponse)
authResponse.setResponseCode(ApplicationConstants.INTERNAL_ERROR_CODE);
authResponse.setStatus(StatusType.FAILURE);
authResponse.setResponseMsg(ApplicationConstants.INTERNAL_ERROR_MESSAGE);
return authResponse;
private AuthResponse setAuthResponseSuccess(AuthResponse authResponse)
authResponse.setResponseCode(ApplicationConstants.OK);
authResponse.setStatus(StatusType.SUCCESS);
authResponse.setResponseMsg(ApplicationConstants.LOGIN_SUCCESS);
return authResponse;
【问题讨论】:
如果有人想看拦截器,请告诉我 你在使用 spring-security 吗? 不!我想手动完成。这可能吗? 我提出了一个解决方案。请检查以下内容。 空间不足...我不认为应用程序服务器保留了 JSESSIONID,而是对应用程序的后续调用包含 JSESSIONID 作为调用的一部分。如果已经存在一个新的 JSESSIONID,则应用程序服务器不会发出新的 JSESSIONID。这就是为什么重新启动浏览器会产生一个新的 JSESSIONID。因为对应用程序的新(新)调用不会包含 JSESSIONID 值,因此会强制应用程序服务器生成一个新的。 【参考方案1】:浏览器上剩余的 JSESSIONID 没有任何问题,只要它已经无效。 JSESSIONID 只是一堆不包含您的实际数据的随机字符。
但是我怀疑您的问题是您在班级级别使用了@SessionAttributes
注释,并且您尝试了session.invalidate()
。在上一个会话失效后的这种情况下,Spring 会自动为您创建一个新会话(和 JSESSIONID),因为它必须将指定的模型属性持久化到会话中。
IMO 更好的方法是创建一个没有 @SessionAttributes
的新控制器,并从那里使您的会话无效。
【讨论】:
我已经在上面发布了我的整个代码,并且我没有在类级别使用@SessionAttribute。请看一下,如果那里有问题,请告诉我:) 我猜可以用cookie添加过期属性吧? 根据我的第一句话回答,只要 JSESSIONID 已经失效,浏览器上的剩余部分就没有任何问题。可能你对 HttpSession 的理解不正确? 问题是,如果有人尝试登录,则在注销后,不会创建新的 JSESSIONID。保留在浏览器 ID 中的 ID 使用新参数重新初始化并发回。因此,即使有 10 个用户使用该系统,JSESSIONID 也保持不变。我不能在注销后强制使用新的 JSESSIONID 吗?希望我的问题很清楚。 顺便说一句,它是一个前端和后端分离的单页应用程序。【参考方案2】:我能想到的一种方法是在注销操作时删除JSESSIONID
cookie。删除 cookie 的方法是将其年龄设置为零,如下所示。
Cookie cookie = new Cookie();
cookie.setValue(null);
cookie.setMaxAge(0);
cookie.setPath("/");
在这里,我已将路径添加为 root。请检查浏览器中的JSESSIONID
cookie 以获取正确的路径。
一旦你有了这个,把它添加到响应中
response.addCookie(cookie);
您可以将此代码放入您的exitPrime()
方法中。
【讨论】:
cookie 值可以为空吗?还是可以有 0 长度? 是的。您可以使用零长度字符串,但这并不重要,因为 cookie 将立即过期,因为它的maxAge
设置为零。
我使用你给出的代码如下Cookie cookie = new Cookie("JSESSION","");//it din allow to be null cookie.setValue(" ");//Same reason as above. Rest of the code remained the same.
这确实解决了问题并清除了cookie,但这导致另一个想法是服务器是否创建了一个与前一个等效的会话ID在它被无效之后(在前一种情况下?)但仍然投票给你! :D
:)。当您使会话无效时,它只会破坏服务器端的session object
,并且不会从浏览器中删除会话cookie。因此,作为属性存储在会话对象中的所有数据(使其有效)也会丢失。因此,下次当服务器从 cookie 中获取无效的会话 id 时,它会检查是否有与之关联的会话对象,如果没有(这将是无效会话的情况),它只是创建一个新的会话对象并将其与它在 cookie 中收到的会话 ID 相关联。【参考方案3】:
经过一番试验后,我得出一个结论,如果您希望浏览器 cookie 值保持不变,那么就不要做任何事情,上面的代码对您来说可以正常工作。另一方面,如果您希望 cookie 的输出类似于
Set-Cookie: JSESSIONID=""; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/
那你可以拿这段代码sn-p试试看。
private void handleLogOutResponseCookie(HttpServletResponse response)
Cookie[] cookies = request.getCookies();
for (Cookie cookie : cookies)
cookie.setMaxAge(0);
cookie.setValue(null);
cookie.setPath("/");
response.addCookie(cookie);
这将解决问题并在您注销时销毁 cookie。
【讨论】:
从请求中清除所有 cookie 是不可取的。可能有一些应用程序没有创建,例如负载平衡器 cookie 或 Web 服务器跟踪 cookie。 此外,您的应用程序可能出于某种原因使用(或将来会在某处使用)cookie。我建议只使名为 JSESSIONID 的 cookie 无效。【参考方案4】:不确定它是否仍然是实际的,但可以像这样扩展 LogoutFilter 以指定注销时要执行的确切步骤,包括自定义 cookie 失效。
<beans:bean id="sessionInvalidationFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter">
<beans:property name="filterProcessesUrl" value="/logout"/>
<beans:constructor-arg>
<beans:array>
<beans:bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"/>
<beans:bean class="org.springframework.security.web.authentication.logout.CookieClearingLogoutHandler">
<beans:constructor-arg value="JSESSIONID"/>
</beans:bean>
</beans:array>
</beans:constructor-arg>
</beans:bean>
【讨论】:
【参考方案5】:之前列出的方法对我不起作用,但经过一些修改后我让它起作用了,尽管如此 YMMV,我只进行了有限的测试。
protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException
HttpSession session = req.getSession(false);
if (session != null)
String sessionId = session.getId();
session.invalidate();
Cookie[] cookies = req.getCookies();
for (Cookie cookie : cookies)
if (sessionId.equalsIgnoreCase(cookie.getValue()))
cookie.setMaxAge(0);
cookie.setValue(null);
cookie.setDomain(req.getServerName());
cookie.setPath(req.getServletContext().getContextPath() + "/");
cookie.setSecure(req.isSecure());
res.addCookie(cookie);
break;
【讨论】:
【参考方案6】:Tomcat 在上下文路径的末尾附加一个斜杠。现在,当您设置 delete-cookie 属性时,Spring 会尝试查找路径的 cookie,而该路径的末尾没有斜线。因为没有找到,所以cookie不会被移除,导致显示的是session过期页面而不是登录页面。
以下解决方法可以解决问题。
public void logout(HttpServletRequest request, HttpServletResponse response,
Authentication auth)
Cookie cookieWithSlash = new Cookie("JSESSIONID", null);
//Tomcat adds extra slash at the end of context path (e.g. "/foo/")
cookieWithSlash.setPath(request.getContextPath() + "/");
cookieWithSlash.setMaxAge(0);
Cookie cookieWithoutSlash = new Cookie("JSESSIONID", null);
//JBoss doesn't add extra slash at the end of context path (e.g. "/foo")
cookieWithoutSlash.setPath(request.getContextPath());
cookieWithoutSlash.setMaxAge(0);
//Remove cookies on logout so that invalidSessionURL (session timeout) is not displayed on proper logout event
response.addCookie(cookieWithSlash); //For Tomcat
response.addCookie(cookieWithoutSlash); //For JBoss
【讨论】:
谢谢。使用 Grails 2.4.4以上是关于注销会在浏览器上留下 JSESSIONID。如何清除它?的主要内容,如果未能解决你的问题,请参考以下文章