前端使用AngularJS2框架,Server用java写的,工程师写好了,现在需要增加一个判断用户登录超时的功能。用户登录后,使用如下代码将登录sessionID和时间放到Sessioncache中,实质是一个hashmap,key是sessionID,value是time。
String sessionId = req.getSession().getId();
long time = System.currentTimeMillis();
SessionCache.getInstance().getCache().put(sessionId, time);
使用路由守卫,每次用户进行页面跳转向服务端发起请求时,进行一次check。因为同一用户使用同一个浏览器时,在关闭浏览器之前sessionID是一样的(关于sessionID的解释这个博客写的浅显易懂):
好,session 诞生了,从上面的描述来讲,它就是在一次会话中解决2次HTTP的请求的关联,让它们产生联系,让2两个页面都能读取到找个这个全局的session信息。session信息存在于服务器端,所以也就很好的解决了安全问题。
所以使用sessionID从SessionCache中查询,如果没查到,则跳转到login页面;如果查到了,则获取其value即时间,用当前时间与其做差,如果超过一段时间比如10分钟,则跳转到login页面,没超过则正常跳转。思路是比较清晰的。
我测试的时候,都是在本地测试的,webstorm调试前端,intellij调试后端。但是发现同一用户登录后,页面跳转时向服务端发送请求的sessionID跟登录时的不一样,而且每次都不一样。经过查询,是跨域的问题,解决跨域问题,加一个filter类即可。下面是我的filter类代码:
package com.siemens.ct.smartgrid.auth.controller;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Authentication for application
*/
public class AuthenticationFilter implements Filter {
public FilterConfig config;
public void init(FilterConfig filterConfig) throws ServletException {
config = filterConfig;
}
// Just for debug with webstorm sending cross domain message
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse rsp= (HttpServletResponse) response;
rsp.setHeader("Access-Control-Allow-Origin", req.getHeader("Origin"));
rsp.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
rsp.setHeader("Access-Control-Allow-Methods","POST,GET,OPTIONS,DELETE");
rsp.setHeader("Access-Control-Max-Age","3600");
rsp.setHeader("Access-Control-Allow-Credentials","true");
rsp.addCookie(new Cookie("JSSESIONID",req.getSession().getId()));
chain.doFilter(request, rsp);
}
public void destroy() {
this.config = null;
}
}
这个类本来是为了解决了跨域的问题。为了解决sessionID不一致,参考这篇博客,和这篇文章,在**后端**java程序中,用
rsp.setHeader("Access-Control-Allow-Origin", req.getHeader("Origin"));
这一行替换掉了原来的rsp.setHeader("Access-Control-Allow-Origin", '*');
。
同时增加rsp.setHeader("Access-Control-Allow-Credentials","true");
这一行(如果原来没有)。
除了后端外,前端angular提交数据的时候,在httpOption中增加了withCredentials: true
完整的httpOption和提交数据部分:
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json'
}),
withCredentials: true
};
this.http.post<boolean>('http://localhost:8080/ecfm/api/auth/check', user, httpOptions);
};
再启动程序调试就会发现都sessionID都一致了。
总结:
后端:在filter类中修改"Access-Control-Allow-Origin"
,增加rsp.setHeader("Access-Control-Allow-Credentials","true");
(如果原来没有)
前端:在httpOption中增加withCredentials
属性。