spring boot cors 动态添加以及cookie 处理
spring boot 4.2 之后直接支持基于注解解决了,使用很简单,但是需要严格控制跨域请求的就需要一些调整了
解决方法
自定义CorsFilter,自己创建一个bean,传入自定义的CorsConfigurationSource,CorsConfigurationSource 需要配置
一个匹配模式,模式匹配需要配置一个CorsConfiguration通过CorsConfiguration 我们可以解决动态配置的问题
对于不同的模式我们可以使用不同的CorsConfiguration,但是因为默认bean 是单例的,我们可以设计request 模式的scope
解决
参考代码
- cors 定义
package com.dalong.corsapp;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@SpringBootApplication
public class CorsappApplication {
// 静态配置
public static List<String> orgins =new ArrayList<>();
public static void main(String[] args) {
orgins.add("http://localhost:8080");
orgins.add("http://127.0.0.1:8080");
SpringApplication.run(CorsappApplication.class, args);
}
@Bean
public CorsFilter corsFilter(){
CorsFilter corsFilter = new CorsFilter(corsConfigurationSource());
return corsFilter;
}
// 基于scope解决单例问题
@Bean
@Scope(value = "request",proxyMode = ScopedProxyMode.TARGET_CLASS)
public CorsConfigurationSource corsConfigurationSource() {
System.out.println("create ");
CorsConfiguration configuration = new CorsConfiguration();
// orgins should be cache
configuration.setAllowedOrigins(orgins);
configuration.setAllowedMethods(Arrays.asList("*"));
configuration.setAllowCredentials(true);
configuration.setAllowedHeaders(Collections.singletonList("*"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
- 操作cors origin
@RestController
public class Api {
@GetMapping(value = {"/demo"})
public String demo(@CookieValue(value = "name",required = false) String name){
return name;
}
@GetMapping(value = {"/add"})
public String add(){
CorsappApplication.orgins.add("http://dalongrongapp.com:8080");
return "ok";
}
}
参考使用
- 一个js cookie服务
@Controller
public class Cookie {
@GetMapping(value = {"/js"})
public void c(HttpServletRequest request, HttpServletResponse response) {
ResponseCookie cookie = ResponseCookie.from("name", UUID.randomUUID().toString()) // key & value
.httpOnly(true)
.secure(true)
.path("/")
.sameSite("None")
.build();
response.setContentType("application/x-javascript");
response.setHeader(HttpHeaders.SET_COOKIE, cookie.toString());
}
}
- web 集成
index.html (独立web,会有跨域问题)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="http://localhost:3000/js"></script>
</head>
<body>
demo app
<script>
axios.defaults.withCredentials = true;
axios.defaults.timeout = 120000;
axios.get('http://localhost:3000/demo')
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
</script>
</body>
</html>
- 运行说明
静态站点使用8080端口,3000 是web服务的(cors支持)
说明
对于动态添加需要注意请求origin的cache,不然说明很多会有问题的
参考资料
https://docs.spring.io/spring-security/site/docs/4.2.19.BUILD-SNAPSHOT/reference/html/cors.html