跨域:简述"跨域"的几种常见解决方案

跨域:简述"跨域"的几种常见解决方案


  1. 跨域:简述"跨域"的概念与造成原因
  2. 跨域:简述"跨域"的几种常见解决方案

出于安全原因,浏览器禁止对驻留在当前源之外的资源进行AJAX调用。

跨源资源共享(CORS)是大多数浏览器实现的W3C规范,允许以灵活的方式指定授权的跨域请求类型,而不是使用IFrame或JSONP等安全性较低且功能较弱的黑客。

方法一:使用@CorsConfiguration

/**
 * 
 * 设置跨域请求的配置类
 */
@Configuration
public class CorsConfig {
    private CorsConfiguration buildConfig() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        	// 1. 设置访问源地址
        	corsConfiguration.addAllowedOrigin("*"); 
        	// 2. 设置访问源请求头
        	corsConfiguration.addAllowedHeader("*"); 
        	 // 3. 设置访问源请求方法
        	corsConfiguration.addAllowedMethod("*");
        
        return corsConfiguration;
    }

    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        	// 4. 对接口配置跨域设置
        	source.registerCorsConfiguration("/**", buildConfig()); 
        	
        return new CorsFilter(source);
    }
}

在上述代码中“ * ”代表全部。” ** ”代表适配所有接口。

其中addAllowedOrigin(String origin)方法是追加访问源地址。如果不使用”*”(即允许全部访问源),则可以配置多条访问源来做控制。 例如:

corsConfiguration.addAllowedOrigin("http://www.a.cn/"); 
corsConfiguration.addAllowedOrigin("http://test.b.cn/"); 

CorsConfiguration类的官方文档中除了addAllowedOrigin(String origin)方法,还有setAllowedOrigins(List allowedOrigins)方法,其实现如下:

public void setAllowedOrigins(List<String> allowedOrigins) {
	this.allowedOrigins = allowedOrigins != null?new ArrayList(allowedOrigins):null;
}

addAllowedOrigin是追加访问源地址,而setAllowedOrigins是可以直接设置多条访问源。 根据上述源码可以得知,setAllowedOrigins会覆盖this.allowedOrigins。所以在配置访问源地址时, addAllowedOrigin方法要写在setAllowedOrigins后面,当然了,一般情况下不建议这两个方法混着用。

addAllowedHeader、addAllowedMethod、registerCorsConfiguration方法和addAllowedOrigin的源码类似,这里就不一一介绍了。

方法二:使用WebMvcConfigurer

@Configuration
public class MyConfiguration {

    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurerAdapter() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                //registry.addMapping("/**");
                registry.addMapping("/api/**")
					    .allowedOrigins("http://domain2.com")
						.allowedMethods("PUT", "DELETE")
						.allowedHeaders("header1", "header2", "header3")
						.exposedHeaders("header1", "header2")
						.allowCredentials(false).maxAge(3600);
            }
        };
    }
}

@Configuration
class CORSConfiguration implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        //registry.addMapping("/**");
        registry.addMapping("/api/**")
            .allowedOrigins("http://domain2.com")
            .allowedMethods("PUT", "DELETE")
            .allowedHeaders("header1", "header2", "header3")
            .exposedHeaders("header1", "header2")
            .allowCredentials(false).maxAge(3600);
    }
}

方法三、使用@CrossOrgin注解

@CrossOrgin注解既可以用于方法也可以用于整个Controller层。

当控制器和方法均有CORS配置时,Spring将组合两个注释属性以创建合并的CORS配置。

  1. 在整个Controller层使用@CrossOrgin注解配置
@CrossOrigin(origins = "http://domain2.com", maxAge = 3600)
@RestController
@RequestMapping("/account")
public class AccountController {

	@GetMapping("/{id}")
	public Account retrieve(@PathVariable Long id) {
		// ...
	}

	@DeleteMapping("/{id}")
	public void remove(@PathVariable Long id) {
		// ...
	}
}
  1. 在Controller层中的方法使用@CrossOrgin注解配置
@RestController
@RequestMapping("/account")
public class AccountController {

	@CrossOrigin
	@GetMapping("/{id}")
	public Account retrieve(@PathVariable Long id) {
		// ...
	}

	@DeleteMapping("/{id}")
	public void remove(@PathVariable Long id) {
		// ...
	}
}
  1. 在Controller层控制器和方法都使用@CrossOrgin注解配置
@CrossOrigin(maxAge = 3600)
@RestController
@RequestMapping("/account")
public class AccountController {

	@CrossOrigin(origins = "http://domain2.com")
	@GetMapping("/{id}")
	public Account retrieve(@PathVariable Long id) {
		// ...
	}

	@DeleteMapping("/{id}")
	public void remove(@PathVariable Long id) {
		// ...
	}
}

如果使用的是Spring Security,必须确保在Spring Security级别启用CORS,以允许它利用Spring MVC级别定义的配置。

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.cors().and()...
	}
}

方法四、使用Filter配置Header

@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("ok");
            return;
        }
        
        chain.doFilter(request, response);
    }
    
    @Override
    public void destroy() {
    }
    
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }
}

方法五、使用Nginx配置

如果我们在项目中使用了Nginx,可以在Nginx中添加以下的配置来解决跨域(原理其实和Filter类似)。

location / {
   add_header Access-Control-Allow-Origin *;
   add_header Access-Control-Allow-Headers X-Requested-With;
   add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;

   if ($request_method = 'OPTIONS') {
     return 204;
   }
}
©️2020 CSDN 皮肤主题: Age of Ai 设计师:meimeiellie 返回首页