栏目分类:
子分类:
返回
终身学习网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
终身学习网 > IT > 软件开发 > 后端开发 > Java

浅谈跨域问题,以及跨域问题如何处理

Java 更新时间:发布时间: 百科书网 趣学号
一、概述

我们在开发过程中经常会遇到前后端分离而导致的跨域问题,导致无法获取返回结果。跨域就像分离前端和后端的一道鸿沟,君在这边,她在那边,两两不能往来。

①、什么是跨域

跨域(CORS)是指不同域名之间相互访问。指的是浏览器不能执行其他网站的脚本,它是由浏览器的同源策略所造成的,是浏览器对于Javascript所定义的安全限制策略。

②、什么情况会跨域
  • 同一协议, 如http或https
  • 同一IP地址, 如127.0.0.1
  • 同一端口, 如8080

以上三个条件中有一个条件不同就会产生跨域问题。

③、为什么要设计同源策略
  • 其中一个重要原因就是对cookie的保护,cookie 中存着sessionID 。黑客一旦获取了sessionID 并且在有效期内 就可以登录,这里我们可以简单的认为sessionID 全等于 账户加密码,想想当我们访问了一个恶意网站,如果没有同源策略,那么这个网站就能通过js 访问document.cookie 得到用户关于的各个网站的sessionID 其中可能有银行网站等等
  • 通过已经建立好的session连接进行攻击的 这里有一个专有名词 美名曰 CSRF 攻击 ,需要注意的是同源策略无法完全防御CSRF 这里需要服务端配合

再举个例子,现在我扮演坏人,我通过一个iframe 加载某宝的登录页面,等傻傻的用户登录我的网站的时候,我就把这个页面弹出,用户一看,阿里唉大公司肯定安全,就屁颠屁颠的输入了密码注意如果没有同源策略,我这个恶意网站就能通过dom操作获取到用户输入的值,从而控制该账户所以同源策略是绝对必要的。

二、解决方案 ①、准备工作

准备两个SpringBoot Module

在CrossDomainA中新增一个HTML页面,用于访问CrossDomainB下的user请求




    
    Tile







在CrossDomainB中新增一个User实体类和UserController控制器

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private String userName;
    private String password;
}
@RestController
public class UserController {
    @RequestMapping("/user")
    public User getUser(HttpServletResponse response) {
        return new User("彭焕智", "666");
    }
}

其中CrossDomainB监听8081端口,CrossDomainA监听8080端口,启动项目,访问8081,正常访问

通过CrossDomainA去访问CrossDomainB呢

②、添加响应头解决跨域

IE10以下不支持

response新增一个header

@RestController
public class UserController {
    @RequestMapping("/user")
    public User getUser(HttpServletResponse response) {
        //Access-Control-Allow-Origin允许跨域,*表示允许所有人都允许跨域,也可以指定主机
        response.setHeader("Access-Control-Allow-Origin","http://localhost:8080");
        return new User("彭焕智", "666");
    }
}

实际上CrossDomainA去访问CrossDomainB的时候发送的是两个请求,第一个是option类型的域检请求,询问CrossDomainB服务器是否支持跨域,如果支持,再发送一个get请求给userController,否则第二个请求就不发了

  • 对于域检请求,他是有一个时间控制的,不是每一次跨域请求都需要进行域检请求,我们可以设置一个时长,当上一次跨域请求到这一次跨域请求间隔时间超出了这个时长,那么再重新发送一个域检请求,否则就直接发送get而不发送域检请求
response.setHeader("Access-Control-Allow-Origin","http://localhost:8080");
response.setHeader("Access-Control-Max-Age","10");

除了可以控制跨域请求和域检请求间隔时长,还可以设置允许的请求方法,携带的headers等等

Access-Control-Allow-Method
Access-Control-Allow-Headers
...

对于SpringBoot中,直接就提供了支持跨域的注解@CrossOrigin

@RestController
public class UserController {
    @RequestMapping("/user")
    @CrossOrigin(origins = {"*"}, maxAge = 3600, methods = {RequestMethod.GET, RequestMethod.POST})
    public User getUser(HttpServletResponse response) {
        return new User("彭焕智", "666");
    }
}
③、手写Java反向代理

原理就是,我们通过CrossDomainA去访问CrossDomainB的时候,让CrossDomainA生成一个我们用户自己的一个代理,通过这个代理再去访问CrossDomainB,就好比我们自己去访问CrossDomainB一样,相当于是服务器和服务器之间去请求了,不再是通过浏览器访问,代理收到响应后,再把响应返回给用户

package com.phz.cross_domain.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;


@RestController
public class ProxyController {
    @Value("${proxy.address}")
    //proxy.address=http://127.0.0.1:8081
    private String proxyAddress;

    @Resource
    private RestTemplate restTemplate;

    @RequestMapping("/api
@RestController
public class UserController {
    @RequestMapping("/api/user")
    @CrossOrigin(origins = {"*"}, maxAge = 3600, methods = {RequestMethod.GET, RequestMethod.POST})
    public User getUser(HttpServletResponse response) {
        return new User("彭焕智", "666");
    }

    @RequestMapping("/cross")
    public String cross() {
        return "cross('hello')";
    }
}

三、SpringBoot处理跨域问题

不难,注入一个WebMvcConfigure的实现类,重写一个addCorsMappings方法即可,具体配置理解不难

@Configuration
public class CorsConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
            .allowedOrigins("*")
            .allowCredentials(true)
            .allowedMethods("GET", "POST", "DELETE", "PUT","OPTIONS")
            .maxAge(3600);
    }
}
转载请注明:文章转载自 www.051e.com
本文地址:http://www.051e.com/it/273808.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 ©2023-2025 051e.com

ICP备案号:京ICP备12030808号