SpringSecurity 跨域资源共享(CORS)的实现
作者:wx6875a567c49bb
浏览器的同源策略(Same-Origin Policy, SOP) 是浏览器最核心、最基础的安全机制之一,本质是为了隔离不同域名的资源,防止恶意网站窃取或篡改其他网站的敏感数据,保障用户隐私和网络安全。“同源” 指的是两个资源的 “协议(Protocol)、域名(Domain)、端口(Port)” 三者完全一致,缺一不可。只要任意一项不同,就属于 “跨源(Cross-Origin)”。
CORS(Cross-Origin Resource Sharing)即跨域资源共享,应用程序会通过 CORS(跨域资源共享)机制来放宽这一严格的(同源)策略,从而允许在特定条件下进行跨源请求。在当前流行的前后端分离架构模式下很可能会用到 CORS。
创建一个页面 src\main\resources\static\index.html,这是一个静态文件,可以直接被访问,页面的访问地址是 http://localhost/index.html,页面中有一个按钮,点击按钮的时候使用 fetch 发起对 http://localhost/hello 的请求。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <button id="getHelloBtn">get hello</button> <script> const getHelloBtn = document.getElementById('getHelloBtn'); getHelloBtn.addEventListener('click', () => { fetch('http://127.0.0.1/hello') .then(res => res.text()) .then(data => { console.log(data); }) }) </script> </body> </html>
因为页面使用的域名是 localhost 和接口使用的是 127.0.0.1 IP 地址,域名不一致,所以请求的响应被阻止了。
此时可以通过配置 CORS 就可以来解决这个同源策略的限制。Spring 提供了 @CrossOrigin 注解,把这个注解加在控制器上:
@RestController public class HelloController { @RequestMapping(value = { "/hello" }, method = RequestMethod.GET) // 允许 http://localhost 域发起对该接口的请求 @CrossOrigin("http://localhost") public String requestMethodName() { return "Hello, Spring!"; } }
再次点击按钮,浏览器控制台中打印出了接口响应的内容:
@CrossOrigin 除了可以用在方法上之外,还可以用在类上,这样整个控制器就都允许跨域访问了。@CrossOrigin 还提供了其他配置参数
public @interface CrossOrigin { @AliasFor("origins") String[] value() default {}; // 允许跨域请求的源 @AliasFor("value") String[] origins() default {}; // 允许跨域请求的源 String[] originPatterns() default {}; // 通过通配符模式匹配允许的来源 String[] allowedHeaders() default {}; // 指定跨域请求中允许携带的请求头 String[] exposedHeaders() default {}; // 指定跨域响应中允许前端读取的响应头 RequestMethod[] methods() default {}; // 指定允许的 HTTP 请求方法 String allowCredentials() default ""; // 指定是否允许跨域请求携带身份凭证, // 若设为 true,origins 不能为 *(必须指定具体来源),否则浏览器会拒绝响应。 String allowPrivateNetwork() default ""; // 控制是否允许来自私有网络(如局域网)的跨域请求 long maxAge() default -1L; // 指定预检请求(Preflight Request)的结果缓存时间(单位:秒) }
通过 @CrossOrigin 注解可以很简单地解决跨域问题,但需要每个控制器都要配置一次,就显得比较啰嗦了,而且一旦需要修改配置工作量就比较大,而且还可能产生一些风险。
Spring Security 也提供了 CORS 的配置,可以进行全局的配置:
@Configuration public class SecurityConfig { @Resource private CustomAuthenticationProvider customAuthenticationProvider; @Bean SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authenticationProvider(customAuthenticationProvider) .httpBasic(Customizer.withDefaults()); http.csrf(c -> c.disable()); http.cors(c -> { CorsConfigurationSource source = request -> { CorsConfiguration config = new CorsConfiguration(); config.setAllowedOrigins(Arrays.asList("http://localhost")); // 允许跨域请求的源 config.setAllowedMethods(Arrays.asList("GET", "POST")); // 指定允许的 HTTP 请求方法 config.setAllowedHeaders(Arrays.asList("*")); // 指定跨域响应中允许前端读取的响应头 return config; }; c.configurationSource(source); }); http.authorizeHttpRequests( auth -> auth .anyRequest().permitAll()); return http.build(); } }
如果需要不同的路径有不同的跨域配置,也没问题:
@Configuration public class SecurityConfig { @Resource private CustomAuthenticationProvider customAuthenticationProvider; @Bean SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authenticationProvider(customAuthenticationProvider) .httpBasic(Customizer.withDefaults()); http.csrf(c -> c.disable()); http.cors(c -> { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); CorsConfiguration config = new CorsConfiguration(); config.setAllowedOrigins(Arrays.asList("http://localhost")); config.setAllowedMethods(Arrays.asList("GET")); config.setAllowedHeaders(Arrays.asList("*")); source.registerCorsConfiguration("/hello", config); // 给指定的路径绑定 CORS 配置 CorsConfiguration config2 = new CorsConfiguration(); config2.setAllowedOrigins(Arrays.asList("http://localhost")); config2.setAllowedMethods(Arrays.asList("POST")); config2.setAllowedHeaders(Arrays.asList("*")); source.registerCorsConfiguration("/aa/bb/cc", config2); // 给指定的路径绑定 CORS 配置 c.configurationSource(source); }); http.authorizeHttpRequests( auth -> auth .anyRequest().permitAll()); return http.build(); } }
到此这篇关于SpringSecurity 跨域资源共享(CORS)的文章就介绍到这了,更多相关SpringSecurity 跨域资源共享内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!