我们先了解下【域】的定义:协议 + 域名 + 端口。三者完全相同则为同域,反之有其一不同均为不同域。那么,什么是跨域请求?当前【发起请求】的域和【请求指向】的域属于不同域时,该次请求称之为跨域请求。简单说A应用只能访问A应用后台传来数据,B应用只能访问B应用后台传来的数据,如果A应用用Ajax获取数据时的URL地址中的协议、端口、域名其中有一个和B应用对应的话,则是A应用跨域了想获取B应用数据,是不允许的。在谈跨域之前,我们先来看看浏览器的同源策略。
01
跨域的几种情况
- 同一域名下允许通信(未指定端口协议)
- 同一域名下不同文件夹允许通信
- 同一域名不同端口不允许通信
- 同一域名不同协议不允许通信
- 域名和域名对应IP不允许通信
- 主域名相同,子域名不同不允许通信
- 同一域名,不同二级域名不允许通信
- 不同域名不允许通信
01
跨域示例如下:
方法1:全局配置
定义配置类,添加@Configuration注解,实现WebMvcConfigurer接口,再重写addCorsMappings方法:
// 请求跨域
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
//添加映射路径
registry.addMapping("/**")
//是否发送Cookie
.allowCredentials(true)
//设置放行哪些原始域 SpringBoot2.4.4下低版本使用.allowedOrigins("*")
.allowedOriginPatterns("*")
//放行哪些请求方式
.allowedMethods(new String[]{"GET", "POST", "PUT", "DELETE"})
//.allowedMethods("*") //或者放行全部
//放行哪些原始请求头部信息
.allowedHeaders("*")
//暴露哪些原始请求头部信息
.exposedHeaders("*");
}
}
方法2:局部跨域
Controller层在需要跨域的类或者方法上加上@CrossOrigin该注解即可。
@CrossOrigin(origins = "*",maxAge = 3600)
public class UserController {
final UserService userService;
@GetMapping("/getOne/{id}")
public User getOne(@PathVariable("id") Integer id) {
return userService.getById(id);
}
我们也可以设置更小的粒度,在方法上设置跨域:
@Controller
@RequestMapping("/shop")
public class ShopController {
@GetMapping("/")
@ResponseBody
//更小的解决跨域 设置只能某些地址访问
@CrossOrigin(originPatterns = "http://localhost:8080")
public Map<String, Object> findAll() {
//返回数据
return DataSchool.getStudents();
}
}
方法3:定义跨域过滤器
1)编写过滤器
// 跨域过滤器
@Component
public class CORSFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
//*号表示对所有请求都允许跨域访问
HttpServletResponse res = (HttpServletResponse) response;
res.addHeader("Access-Control-Allow-Credentials", "true");
res.addHeader("Access-Control-Allow-Origin", "*");
res.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
res.addHeader("Access-Control-Allow-Headers", "Content-Type,X-CAF-Authorization-Token,sessionToken,X-TOKEN");
if (((HttpServletRequest) request).getMethod().equals("OPTIONS")) {
response.getWriter().println("Success");
return;
}
chain.doFilter(request, response);
}
@Override
public void destroy() {
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
}
2)注册过滤器
@Configuration
public class CorsConfig {
@Bean
public CorsFilter corsFilter() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.addAllowedOrigin("*");
corsConfiguration.addAllowedHeader("*");
corsConfiguration.addAllowedMethod("*");
corsConfiguration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
return new CorsFilter(urlBasedCorsConfigurationSource);
}
}
03
小结
网络安全涉及的范围非常广,跨域仅仅是「浏览器安全」中的一种,开发的时候也经常会碰到,希望大家多多留意。
加关注这种话银家怎么好意思说出口嘛