记录解决SpringBoot前后端分离跨域导致的图片验证码Sessionid不一致(也即空指针异常问题)

问题

最近在给项目开发登录注册功能,在登录的图片验证码上出现了问题,报了空指针异常。
逻辑是这样的:在登录页面,前端通过验证码接口先请求验证码,然后输入用户名密码和验证码之后,请求登录接口。在验证码接口中我用session保存验证码,在登录接口中我从session取出验证码进行校验。 postman测试没有问题,但是前端在测试时报了空指针异常。
在这里插入图片描述
于是我查看后端日志,发现请求验证码时返回给前端的sessionId和前端发送登录请求时所携带的sessionId不一致,所以后端拿到的sessionId是没有对应的验证码的,于是报了空指针异常。
在这里插入图片描述
通过查阅网上的各种信息,我们了解到这是因为跨域问题导致的,跨域我是配置过的,按照网上的办法前后端都配置了相应的跨域设置,但是依然没有解决问题。
具体可以参考链接试试,也是有人成功的:https://www.cnblogs.com/jpfss/p/9081570.html

解决办法

这个问题困扰了我们好几天,期间也是尝试过很多方法,无论是前端的跨域配置,还是后端的跨域配置都试过了,但是问题还是没有解决,不知道是不是因为我将shiro整合JWT的时候关闭了shiro的session导致的,并不清楚,我把shiro的session打开后也没有解决问题。
既然跨域这条路走不通,我们就换条路走,下面给出两种解决方法

方法一:不使用session

不使用session来实现验证码的验证,将验证码转存到redis或者数据库中,前端在通过验证码接口获取验证码时除了返回验证码本身,还要返回验证码的id,那么前端在登录的时候也要把验证码id和用户输入的验证码传给后端进行验证。这个方法并没有使用session,所以并不重点展开,我主要介绍第二种方法。

方法二:取消验证码接口,只保留登录接口来实现获取图片验证码和登录功能

使用session时对同一个页面多次刷新是不会改变sessionid的
在这里插入图片描述
既然sessionid不会改变,也就解决了我们之前的问题,那么新的问题是如何只通过一个接口实现即能返回验证码,又能实现登录功能呢。

在这里插入图片描述
我在开发登录接口时,会在登录失败时返回code为400的错误信息,在登录成功时返回code为200,也就是说只要前端发送的请求中用户名,密码,验证码任意一个为空,后端都会返回错误信息,那么只要在返回错误信息的同时将验证码的base64格式传给前端就可以了。

@PostMapping("login")
    public Result login(@RequestBody User loginUser , HttpServletResponse response, HttpServletRequest request) throws IOException {
    
    
        //检验loginUser元素是否完整,不完整则返回错误信息
        String message = new Judge().judgeUser(loginUser);
        if(message != "none"){
    
    //这是我封装的判断方法,如果message不为none的话,说明登录信息不完整,此时就可以返回验证码了
            //生成验证码
            String code = VerifyCodeUtils.generateVerifyCode(4);
            //验证码放入session
            request.getSession().setAttribute("code",code);
            System.out.println("getImageSession:"+request.getSession().getId());
            //验证码存入图片
            ByteArrayOutputStream bs = new ByteArrayOutputStream();
            VerifyCodeUtils.outputImage(110,30,bs,code);
            //将图片转成二进制并进行Base64编码
            String imgsrc = Base64.byteArrayToBase64(bs.toByteArray());
            System.out.println(imgsrc);
            return Result.fail(message,"data:image/png;base64,"+imgsrc);
        }

        //验证图片验证码
        String codes = (String)request.getSession().getAttribute("code");
        System.out.println("loginSession:"+request.getSession().getId());
        System.out.println("codes:"+codes);
        System.out.println("loginUser.getCode():"+loginUser.getCode());
        try {
    
    
            if (!codes.equalsIgnoreCase(loginUser.getCode())) {
    
    //equalsIgnoreCase忽略大小写
                return Result.fail("验证码错误");
            }
        }catch (NullPointerException e){
    
    
            e.printStackTrace();
            return Result.fail("空指针异常");
        }
        //后面就是基本的登录逻辑了,和本问题无关,所以就不贴出来了。
    }

那么前端要做的事也就很简单了,在用户访问登录界面时发送一个空请求给后端,从而拿到验证码图片的base64格式,再加上img src标签后就可以展示图片了,用户填写完整的登录信息后再给后端发送请求就能实现登录了。
附上前端代码:
一、在点击用户名输入框的时候 发送一个请求获取验证码。

$('.inputName').one("focus", function () {
    
    
        $.ajax({
    
    
            url: 'http://*.*.*.*/user/login',
            type: 'POST',
            contentType: "application/json",
            dataType: 'json',//json 返回值类型
            data: JSON.stringify({
    
    
                username: "" + rt.value,
                password: "" + uu.value,
                code: "" + op.value
            }),//转化为json字符串
            xhrFields: {
    
    

                withCredentials: true

            },
            success: function (datas) {
    
    
                $('.pp').attr("src", datas.data);
            }
        })
    })

二、点击登录的时候 将信息提交给服务的接口

tt[3].onclick = function () {
    
    
        ru.style.display = 'block';
        $.ajax({
    
    
            url: 'http://*.*.*.*/user/login',
            type: 'POST',
            contentType: "application/json",
            dataType: 'json',//json 返回值类型
            data: JSON.stringify({
    
    
                username: "" + rt.value,
                password: "" + uu.value,
                code: "" + op.value
            }),//转化为json字符串
            xhrFields: {
    
    

                withCredentials: true

            },
            success: function (datas) {
    
    
                console.log(datas);
                if (datas.code == '200') {
    
    
                    ru.style.display = 'none';
                    ty.innerHTML = datas.msg;
                    ty.style.display = 'block';
                    tt[3].setAttribute("class", "sub");
                    alert('好兄弟即将起航');
                    var seconds = 3;
                    setInterval(function () {
    
    
                        seconds--;
                        if (seconds == 0) {
    
    
                            window.location.href = "../main_page.html";
                        }
                    }, 1000);
                }
                else {
    
    
                    ru.style.display = 'none';
                    ty.innerHTML = datas.msg;
                    ty.style.display = 'block';
                }
            }
        });
    }

最后自然是成功解决了验证码报空指针的问题了
在这里插入图片描述

在这里插入图片描述

Guess you like

Origin blog.csdn.net/sgsx11/article/details/120288407