关于前后端分离存在跨域、sessionid变动的情况讨论

时间:2024-03-16 12:43:37

说明:最近公司开发一款产品,前段使用js 后端使用springboot 期间调试接口的时候会出现跨域问题,及解决之后又遇到的问题,

1:接口调试的时候遇到的问题,前段访问我的接口,存在跨域:

表现为:

关于前后端分离存在跨域、sessionid变动的情况讨论

表明存在跨域行为;

解决:使用拦截器进行解决:

①:定义一个拦截器实现handlerInterceptor

@Component
public class CorsInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse response, Object o) throws Exception {
        response.addHeader("Access-Control-Allow-Origin", "*");
        response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD");
        response.addHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
        response.addHeader("Access-Control-Max-Age", "3600");
        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 {

    }
}

②:设置拦截请求的路径,这里对所有的请求进行拦截;

@Configuration
public class MonitorInterceptor extends WebMvcConfigurerAdapter {

    private CorsInterceptor corsInterceptor;

    private LoginInterceptor loginInterceptor;

    @Autowired
    public MonitorInterceptor(CorsInterceptor corsInterceptor, LoginInterceptor loginInterceptor) {
        this.corsInterceptor = corsInterceptor;
        this.loginInterceptor = loginInterceptor;
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        super.addInterceptors(registry);
        registry.addInterceptor(corsInterceptor).addPathPatterns("/v1/**");
//        registry.addInterceptor(corsInterceptor).addPathPatterns("/v2/**");
//        registry.addInterceptor(loginInterceptor).addPathPatterns("/v1/**");
//        registry.addInterceptor(loginInterceptor).excludePathPatterns("/v2/**");
    }

通过以上方式即可实现跨域问题,但是业务中存在登录验证功能,也就是对于对应的功能,如果没有登录,不能访问数据

这里我还是通过拦截器进行操作的;代码如下:

@Configuration
public class MonitorInterceptor extends WebMvcConfigurerAdapter {

    private CorsInterceptor corsInterceptor;

    private LoginInterceptor loginInterceptor;

    @Autowired
    public MonitorInterceptor(CorsInterceptor corsInterceptor, LoginInterceptor loginInterceptor) {
        this.corsInterceptor = corsInterceptor;
        this.loginInterceptor = loginInterceptor;
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        super.addInterceptors(registry);
        registry.addInterceptor(corsInterceptor).addPathPatterns("/v1/**");
        registry.addInterceptor(corsInterceptor).addPathPatterns("/v2/**");
        registry.addInterceptor(loginInterceptor).addPathPatterns("/v1/**");//添加拦截路径,
        registry.addInterceptor(loginInterceptor).excludePathPatterns("/v2/**");//将登录请求的路径释放,即不进行拦截
    }

@Component
public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
//        httpServletResponse.setHeader("Accessx-Control-Allow-Origin", "*");
//        httpServletResponse.setHeader("Access-Control-Allow-Headers", "Authorization");

        UserDTO user = (UserDTO) httpServletRequest.getSession().getAttribute("user");
        if (user == null) {
            httpServletResponse.getOutputStream().print(BaseStatusEnums.NOT_AUTHORITY.getTag());
            return false;
        }
        return true;
    }

这里通过验证获取sessio来判断是否有该用户,当然在登录的时候我将用户信息放到session中,如下:

if (userDTO != null) {
    request.getSession().setAttribute("user", userDTO);

    return new ResponseEntity<>(new BasicResult<>(true, "登录成功", userDTO, 0), HttpStatus.OK);
}

可是;这种情况下sessionid是变化的;可通过断点查看和前段中cookie中是否一样

关于前后端分离存在跨域、sessionid变动的情况讨论


这时候出现的问题就是传说的session跨域问题

@Component
public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
        //添加拦截放在这里
        httpServletResponse.setHeader("Accessx-Control-Allow-Origin", "*");
        httpServletResponse.setHeader("Access-Control-Allow-Headers", "Authorization");

        UserDTO user = (UserDTO) httpServletRequest.getSession().getAttribute("user");
        if (user == null) {
            httpServletResponse.getOutputStream().print(BaseStatusEnums.NOT_AUTHORITY.getTag());
            return false;
        }
        return true;
    }
@Configuration
public class MonitorInterceptor extends WebMvcConfigurerAdapter {

    private CorsInterceptor corsInterceptor;

    private LoginInterceptor loginInterceptor;

    @Autowired
    public MonitorInterceptor(CorsInterceptor corsInterceptor, LoginInterceptor loginInterceptor) {
        this.corsInterceptor = corsInterceptor;
        this.loginInterceptor = loginInterceptor;
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        super.addInterceptors(registry);
//这里去掉,注意和前面对比
//        registry.addInterceptor(corsInterceptor).addPathPatterns("/v1/**");
//        registry.addInterceptor(corsInterceptor).addPathPatterns("/v2/**");
        registry.addInterceptor(loginInterceptor).addPathPatterns("/v1/**");
        registry.addInterceptor(loginInterceptor).excludePathPatterns("/v2/**");
    }

前段需要对应的操作:

$.ajax({
    url: host + $("#submitData").attr("action"),
    type: $("#submitData").attr("method"),
    data: $("#submitData").serialize(),
    dataType: "json",
//每个ajax请求都需要加上这个
    xhrFields: {
        withCredentials: true
    },
    async: isAsync,
    success: function (data) {
        sh(data);
这样的话就解决了跨域问题,但是也存在一个问题,就是如果用户没有登录去访问页面,页面也会报跨域问题,如果用户在登录状态去访问,那么就可以正常使用,不报错误!希望网友看到好的解决方法,能够一起进步,欢迎留言讨论