牛骨文教育服务平台(让学习变的简单)
博文笔记

后台跨域造成session失效

创建时间:2017-06-12 投稿人: 浏览次数:5754

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




声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。