主要介绍了前后端分离
vue+springboot
跨域
session+cookie
失效问题的解决方法,解决过程也很简单(该方法也适用于跨站请求)
首先登陆成功时将用户存在
session
中,后续请求在将用户从
session
中取出检查。后续请求取出的用户都为
null
。
首先发现
sessionID
不一致,导致每一次都是新的会话,当然不可能存在用户了。然后发现
cookie
浏览器不能自动保存,服务 器响应set-cookie
了
搜索问题,发现跨域,服务器响应的
setCookie
浏览器无法保存,而且就算保存了域名不同也不能携带。
第一步:
后台添加过滤器,因为前后端分离,不可能每个方法都写一遍,所以添加过滤器统一处理。
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebFilter(urlPatterns = "/*", filterName = "CORSFilter")
public class CORSFilter implements Filter {
@Override
public void destroy() {
}
/**
* 此过滤器只是处理跨域问题
* @param servletRequest
* @param servletResponse
* @param chain
* @throws ServletException
* @throws IOException
*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws ServletException, IOException {
HttpServletRequest req = (HttpServletRequest) servletRequest;
HttpServletResponse resp = (HttpServletResponse) servletResponse;
String origin = req.getHeader("Origin");//注意发布生产时不能这么写,得写死固定可以访问的域名,否则不安全
if(origin == null) {
origin = req.getHeader("Referer");
}
resp.setHeader("Access-Control-Allow-Origin", origin);//这里不能写*,
*代表接受所有域名访问,如写*则下面一行代码无效。谨记
resp.setHeader("Access-Control-Allow-Credentials", "true");//true代表允许携带cookie
chain.doFilter(servletRequest,servletResponse);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
}
springboot2.配置过滤器时,启动类必须加上@ServletComponentScan才会加载过滤器
然后前端配置
使用vue.resource发送请求时配置如下:
main.js中 Vue.http.options.xhr = { withCredentials: true }
使用vue.axios发送请求时配置如下:
axios.defaults.withCredentials = true;
jquery请求带上 xhrFields: {withCredentials: true}, crossDomain: true;
$.ajax({
type: "post",
url: "",
xhrFields: {withCredentials: true},
crossDomain: true,
data: {username:$("#username").val()},
dataType: "json",
success: function(data){ }
});
此时问题已解决。
如果还有问题,则是因为部分浏览器为了防止csrf等漏洞,需要设置samesite属性,像nodejs是是有专门的方法设置,然java后端的cookie现在还没有对应的设置方法,目前只能手动响应,代码如下
//Cookie cookie1 = new Cookie("test","test");
//cookie1.setPath("/");
//cookie1.setHttpOnly(true);
//response.addCookie(cookie1);
String header = response.getHeader("set-cookie");
response.setHeader("set-cookie",header+"; Secure; SameSite=None");
此解决方案:如果涉及到cookie无法设置过期时间,以下方法可解决。
//跨站设置cookie String time = "; Max-Age=1209600; Expires=Tue, " + dateStrtoGMTStr(CommonConstant.FOURTEEN_DAY,CommonConstant.day); response.setHeader("set-cookie", "JSESSIONID=" + WebContext.getSession().getId() + time + "; Path=/; HttpOnly; Secure; SameSite=None"); /* * 格日期变成字符串转为将林尼治时间字符串 */ public String dateStrtoGMTStr(int num,String day) { Calendar cal = Calendar.getInstance();//使用默认时区和语言环境获得一个日历。 if(num > 0){ if(day.equals(CommonConstant.day)){ cal.add(Calendar.DAY_OF_MONTH, +num);//取当前日期+天 }else { cal.add(Calendar.HOUR_OF_DAY, +num);//取当前日期+小时 } } Date time = cal.getTime(); DateFormat format = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss z", Locale.US); format.setTimeZone(TimeZone.getTimeZone("GMT")); return format.format(time); } //设置默认的过期时长,如下:
response.setHeader("set-cookie", "JSESSIONID=" + WebContext.getSession().getId() + "; Path=/; HttpOnly; Secure; SameSite=None");
############################################################# ## session设置默认的会话时长7200秒 取业务系统最长session时长 ## ############################################################# session.maxInactiveIntervalInSeconds=7200 spring.session.store-type=none