SpringCloud+Vue解决跨域Session不一致问题

前言

在做项目时,在登录验证码生成环节,后台生成验证码图像返回给前端,并将验证码置于session,用户填入验证码后传入后台并验证。
但在实验时发现,由于前后端分离项目存在跨域问题,session不再相同,通过输出 sessionId也可以看出,不同请求到达服务端时sessionId是不同的,故需要考虑如何解决Session不一致的问题。

正文

CORS

首先简单讲下CORS。

CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。

它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。

其中关于CORS的请求头参数主要有:

  • Access-Control-Allow-Origin

该字段是必须的。它的值要么是请求时Origin字段的值,要么是一个*,表示接受任意域名的请求。

  • Access-Control-Allow-Credentials

该字段可选。它的值是一个布尔值,表示是否允许发送Cookie。默认情况下为fasle,即Cookie不包括在CORS请求之中。(为了确保session的正常使用,需要将此布尔值设为true

  • Access-Control-Expose-Headers

该字段可选。CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿到其他字段,就必须在Access-Control-Expose-Headers里面指定。

综上,为了sesion的使用,需要开启Credentials

前端开启Credentials

由于前端请求使用的是Vue中的axios,故在axios请求上统一设置Credentials,具体如下:

axios.defaults.withCredentials = true

当然,如果使用的是ajax,也可如下设置:

$.ajax({
		....
        xhrFields: {
            withCredentials: true
        },
        crossDomain: true,
        ...

以上,前端设置完成。

服务端开启Credentials

相应地,对于客户端的参数,服务器端也需要进行设置。

对应客户端的 xhrFields.withCredentials: true 参数,服务器端通过在响应 header 中设置 Access-Control-Allow-Credentials = true 来运行客户端携带证书式访问。

具体如下:

首先添加一个全局拦截器:

package com.hpsyche.hpsycheauthserver.interceptor;

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author Hpsyche
 */
@Component
public class ProcessInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
        httpServletResponse.setHeader("Access-Control-Allow-Origin", httpServletRequest.getHeader("origin"));
        httpServletResponse.setHeader("Access-Control-Allow-Headers", "Content-Type,Content-Length, Authorization, Accept,X-Requested-With");
        httpServletResponse.setHeader("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
        httpServletResponse.setHeader("X-Powered-By","Jetty");
        //重点!!!
        httpServletResponse.setHeader("Access-Control-Allow-Credentials","true");
        String method= httpServletRequest.getMethod();
        if (method.equals("OPTIONS")){
            httpServletResponse.setStatus(200);
            return false;
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
    }

    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
    }
}

声明拦截器后,同时需要配置拦截路径

package com.hpsyche.hpsycheauthserver.config;

import com.hpsyche.hpsycheauthserver.interceptor.GlobalInterceptor;
import com.hpsyche.hpsycheauthserver.interceptor.ProcessInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @author Hpsyche
 */
@Configuration
public class MyWebMvcConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new ProcessInterceptor()).addPathPatterns("/**");
    }
}

以上,再次进行业务处理,发现同一个会话进行时,即使是多次请求,也可确保了sessionId的一致,从而顺利解决了session的跨域问题。

总结

发现问题,是解决问题的第一步!

由于本人水平有限,如大佬们发现我方案中的漏洞,或者有更好的解决方案,望指出!

发布了63 篇原创文章 · 获赞 29 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/Hpsyche/article/details/102941377