后台跨域造成session失效
1.场景还原
最近在笔者在springboot中集成token机制发现了一个隐藏bug:“后台实现跨域,前端运用ajax请求后台接口成功回调;一切看似那么顺利,其实不然,session已经后台失效了,每次请求的sessionId不一致,之前缓存在session中的值取出来都为null,怎么回事?瞬间懵逼”,很多人可能问什么跨域?百度哈,不赘述!
2.寻求症结
①后台实现跨域
@RestController @CrossOrigin @RequestMapping("/user") public class UserController extends BaseController { private Logger logger = LoggerFactory.getLogger(getClass()); @Autowired UserService userService; @Autowired LoginService loginService; @GetMapping(value = "/login") public Map<String,Object> getLogin(String loginName,String password){ String zhangxing = Token.genetateToken(); session.setAttribute("zhangxing",zhangxing); boolean login = false; //储存token String pwd = loginService.getPassword(loginName); Map<String,Object> map = new HashMap<String, Object>(); if(pwd.equals(password)){ login = true; } map.put("login",login); map.put("token",zhangxing); return map; }}没错,后台就凭
@CrossOrigin
一个注解解决了跨域问题。
String zhangxing = Token.genetateToken(); session.setAttribute("zhangxing",zhangxing);
登录并将随机生成的token缓存到session中
②前端ajax请求后台接口
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>token</title> <!-- 引入 echarts.js --> <script type="text/javascript" src="js/jQuery.js"></script> <script type="text/javascript" src="js/cache.js"></script> </head> <body> 用户名:<input type="text" id="username"><br><br> 密 码:<input type="text" id="pwd"><br> <button onclick="getlogin()">登录</button> <!-- xhrFields:{withCredentials:true}, --> <script type="text/javascript"> function getlogin(){ alert($("#username").val()); alert($("#pwd").val()); $.ajax({ type: "get", url: "http://localhost:8089/user/login", data:{ "loginName":$("#username").val(), "password":$("#pwd").val() }, beforeSend: function(XMLHttpRequest){ // alert(pkinds[0]); }, //请求成功回调 success: function(data, textStatus){ alert("进来了"); alert(data.login); alert(data.token); if(data.login){ localStorage.setItem("token",data.token); window.location.href ="good.html"; } }, complete: function(XMLHttpRequest, textStatus){ }, error: function(){ alert("请求网络失败!。。。。。。"); } }); } </script> </body> </html>前端登录成功后得到后台的token,并缓存在localStorage中
localStorage.setItem("token",data.token);并且跳转到另一个界面
window.location.href ="good.html";③good.html前端代码
<html> <head> <meta charset="utf-8"> <title>File upload</title> <script type="text/javascript" src="js/jQuery.js"></script> <script type="text/javascript" src="js/cache.js"></script> </head> <body onload="getAlert()"> <!-- // action="fileupload"对应web.xml中<servlet-mapping>中<url-pattern>的设置. --> <img src="img/feng.jpg" alt=""> <script> function getAlert(){ var token=localStorage.getItem("token"); alert(token) $.ajax({ type: "get", url: "http://localhost:8089/user/getcheck", data:{ "tokenStr":token }, /* xhrFields:{withCredentials:true},*/ beforeSend: function(XMLHttpRequest){ // alert(pkinds[0]); }, //请求成功回调 success: function(data, textStatus){ alert("进来了"); alert(data.check); if(data.check){ window.location.href ="new.html"; localStorage.removeItem("token"); }else{ window.location.href ="login.html"; } }, complete: function(XMLHttpRequest, textStatus){ }, error: function(){ window.location.href ="login.html"; alert("请求网络失败!。。。。。。"); } }); } </script> </body> </html>问题来了?这步前端取出缓存在localStorage的token值
var token=localStorage.getItem("token");然后把取出的token传到后台校验接口,代码如下:
@GetMapping(value = "/getcheck") public Map<String,Object> getCheck(String tokenStr){ String token = (String) session.getAttribute("zhangxing"); boolean check =false; //取出token System.out.println("取出来的值:"+token); if(token != null){ if(token.equals(tokenStr)){ check = true; } } Map<String,Object> map = new HashMap<String, Object>(); map.put("check",check); return map; }这时发现,无论你怎么挣扎,后台取出session的缓存值始终为null
debug之后发现两个controller中的sessionId居然不一致,一脸懵逼!
洗个脸再来,经过逐级排除,笔者定位应该是ajax请求后台跨域接口使session失效,经过一番试错,这个定位果真准!
3.解决方案
只需在ajax中加一个参数设置 xhrFields:{withCredentials:true},完整ajax代码
$.ajax({ type: "get", url: "http://localhost:8089/user/login", data:{ "loginName":$("#username").val(), "password":$("#pwd").val() }, xhrFields:{withCredentials:true}, beforeSend: function(XMLHttpRequest){ // alert(pkinds[0]); }, //请求成功回调 success: function(data, textStatus){ alert("进来了"); alert(data.login); alert(data.token); if(data.login){ localStorage.setItem("token",data.token); window.location.href ="good.html"; } }, complete: function(XMLHttpRequest, textStatus){ }, error: function(){ alert("请求网络失败!。。。。。。"); } });不用质疑,就是这么简单!
效果图:
好了,这个问题就over了,我是张星,欢迎加入博主技术讨论群,群号:313145288
声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。
- 上一篇: 跨域访问会导致session失效
- 下一篇: iframe跨域Session丢失问题的解决办法