在Spring Boot中从浏览器/前端检查会话剩余时间的最佳方法是什么?

huangapple go评论63阅读模式
英文:

Best approach for checking time remaining in Spring Boot Session from browser / front end?

问题

我有一个使用Spring Session和Spring Security的Spring Boot应用程序。 Java @ config。一切都在工作。我可以根据需要动态设置超时时间。

我需要做的是从浏览器检查剩余的会话时间。我想我可以每隔X分钟用ajax请求检查服务器,并让servlet执行session.getLastAccessedTime()session.getMaxInactiveInterval(),然后进行数学计算以查看剩余时间,并返回该值。(不确定是否会刷新lastAccessedTime..)

但是,与所有与Spring相关的内容一样,我的第一直觉通常是错误的。哈。而且,如果浏览器闲置30分钟,似乎在没有发生任何更改的情况下每隔大约一分钟ping服务器是很荒谬的。

我正在寻找是否有更好的解决方案。我想也许我可以在会话超时时设置一个带有时代时间(~1602002425)的cookie。然后我可以使用javascript函数监视该值。但是我没有看到在Spring中这样做的方法。我尝试创建一个CookieSerializer bean来创建一个自定义的cookie名称,但我没有看到设置该值的方法。(似乎会为我创建一个随机的base64字符串值)这可能是Spring阻止我以“错误的方式”做某事。然后每当会话被刷新时,这个cookie也需要被更新。

我已经花了几天时间在线寻找答案,但我看到的都是在服务器端设置会话超时值的方法(我已经可以做到)或者不涉及Spring的前端JavaScript解决方案。

最终目标是在客户端接近超时时弹出一个“会话即将过期..刷新?”的按钮。有没有人有一个解决这个问题的方法?我觉得肯定有人已经解决了这个问题,但我没有看到任何涉及此事的帖子。谢谢!

=======
编辑

我发现我可以使用这段代码设置一个cookie,并在响应体中返回lastAccessed时间。。

	@RequestMapping("/api/timeout")
	@ResponseBody
	public String add(HttpServletRequest request, HttpServletResponse response) throws Exception
	{
		return getLastAccessed(request, response);
	}

	String getLastAccessed(HttpServletRequest request, HttpServletResponse response)
	{
		ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
		HttpSession session =  attr.getRequest().getSession(false);
		long lastAccessed = session.getLastAccessedTime();

		final String cookieName = "timeout";
		final String cookieValue = String.valueOf(lastAccessed);
		final Boolean useSecureCookie = false;
		final int expiryTime = 60 * 60 * 24;  // 24小时,以秒为单位
		final String cookiePath = "/";

		Cookie cookie = new Cookie(cookieName, cookieValue);
		cookie.setSecure(useSecureCookie); 
		cookie.setMaxAge(expiryTime);  
		cookie.setPath(cookiePath);  
		response.addCookie(cookie);

		return String.valueOf(lastAccessed);
	}

但正如我担心的那样,每次检查它时,lastAccessed时间戳都会更新。我需要找到一种在客户端浏览器中检查它而不更新它的方法,或者使用其他方法,该cookie会在任何“其他”请求中被更新,或者使用我目前不知道的其他“Spring方式”来实现这一点。

英文:

I have a Spring Boot app using Spring Session and Spring Security. Java @ config. That's all working. I can set my timeout dynamically as I need.

What I need to do is check the remaining session time from the browser. I guess I could check the server with an ajax request every X minutes and have a servlet do a session.getLastAccessedTime() and a session.getMaxInactiveInterval() and do the math to see what time is remaining and return that. (not sure if that would refresh the lastAccessedTime though..)

But as with everything Spring-related, my first instinct is usually wrong. Ha. Plus if the browser is sitting idle for 30 minutes, seems silly to ping the server every ~minute when nothing has changed.

I'm seeing if anyone has a better solution for this. I'd think that maybe I could set a cookie with a epoch time (~1602002425) when the session will timeout. Then I can watch that value with a javascript function. But I don't see a way to do that in Spring. I tried making a CookieSerializer bean creating a custom cookie name, but there is not a way I can see to SET that value. (looks like a random base64 string value gets created for me) This is probably Spring preventing me from doing something the "wrong way". Then this cookie would need to be updated whenever the Session is refreshed as well.

I've spend a couple days looking from an answer online and all I see are ways to set that Session timeout value servers-side (which I can already so) or JavaScript solutions front-end that are not Spring specific.

End goal is to get a ~"session is about to expire.. refresh?" button to popup when client is getting close to timeout. Does anyone have an approach they've use that works for this? I feel like someone has to have solved this, but I am not seeing any posts that address this. Thanks!

=======
EDIT

I figured out I can use this code to set a cookie and return the lastAccessed time in the response body..

	@RequestMapping("/api/timeout")
	@ResponseBody
	public String add(HttpServletRequest request, HttpServletResponse response) throws Exception
		{
		return getLastAccessed(request, response);
		}

	String getLastAccessed(HttpServletRequest request, HttpServletResponse response)
		{
		ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
		HttpSession session =  attr.getRequest().getSession(false);
		long lastAccessed = session.getLastAccessedTime();

		final String cookieName = "timeout";
		final String cookieValue = String.valueOf(lastAccessed);
		final Boolean useSecureCookie = false;
		final int expiryTime = 60 * 60 * 24;  // 24h in seconds
		final String cookiePath = "/";

		Cookie cookie = new Cookie(cookieName, cookieValue);
		cookie.setSecure(useSecureCookie); 
		cookie.setMaxAge(expiryTime);  
		cookie.setPath(cookiePath);  
		response.addCookie(cookie);

		return String.valueOf(lastAccessed);
		}

But as I feared, the lastAccessed timestamp gets updated every time I check for it. I need to find a way to check that from the client browser without updating it, or another approach that I can use where the cookie either gets update with any 'other' request, or some other "Spring way" of doing this that I am unaware of currently.

答案1

得分: 2

不完全是一个答案,对于你的问题来说有些晚了,但我目前正在尝试通过使用Websockets与客户端进行预联系来解决这个问题。

我当前的方法是创建一个线程,每隔n分钟检查一次超时,并且在调用一个端点时重置计时器(根据此线程检测端点调用)。

https://stackoverflow.com/a/22371901

当计时器接近0时,使用Websockets通知客户端。

关于Websockets的良好概述在这里:https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API

我们正在使用Spring Boot和Angular,所以这个教程也可能有所帮助,但它包含一些特定于Angular的内容。

https://www.javaguides.net/2019/06/spring-boot-angular-8-websocket-example-tutorial.html

如果你还在尝试,祝你好运。

英文:

Not quite an answer, and this is a bit late for your question, but i am currently trying to solve this problem by looking at using websockets to contact the client pre-emptivly .

My current approach is to have a thread that checks the timeout every n minutes, and is reset whenever a endpoint is called (detecting endpoint calls as per this thread)

https://stackoverflow.com/a/22371901

when timer gets close to 0, use websockets to let the client know

Good overview here https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API

We are using spring boot and angular, so this tutorial may also help, but it does have some angular specific stuff.

https://www.javaguides.net/2019/06/spring-boot-angular-8-websocket-example-tutorial.html

good luck if you are still trying at this.

huangapple
  • 本文由 发表于 2020年10月7日 00:59:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/64230495.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定