跨域问题
代理方式
可以使用代理方式解决跨域问题,例如Nginx,或者VUE和REACT使用http-proxy-middleware
React:
const proxy = require("http-proxy-middleware");
module.exports = function(app) {
app.use(
proxy("/api/**", {
target: "http://127.0.0.1:8080",//跨域地址
changeOrigin: true
})
);
};
Vue:
const proxy = require('http-proxy-middleware');
module.exports = {
devServer:{
host: 'localhost',//target host
port: 8080,
//proxy:{'/api':{}},代理器中设置/api,项目中请求路径为/api的替换为target
proxy:{
'/api':{
target: 'http://127.0.0.1:8080',//代理地址,这里设置的地址会代替axios中设置的baseURL
changeOrigin: true,// 如果接口跨域,需要进行这个参数配置
//ws: true, // proxy websockets
//pathRewrite方法重写url
pathRewrite: {
'^/api': '/'
//pathRewrite: {'^/api': '/'} 重写之后url为 http://http://127.0.0.1:8080/xxxx
//pathRewrite: {'^/api': '/api'} 重写之后url为 http://http://127.0.0.1:8080/api/xxxx
}
}}
},
//...
}
跨域方式
一般有些工具可以支持跨域请求,必须使用后台进行配置,运行跨域的请求,例如jsonp,axios;例如使用
为例:
function getList() {
axios.get('/api/getUser', {
params: {
username: 'zahngsan',
currentPage: 1,
pageCount: 50
},
baseURL: 'http://127.0.0.1:8080',
headers: {
'Authorization': 'bearer xxxxxxxxxxx'
},
// proxy: {
// host: '10.176.125.92',
// port: 8081
// },
// withCredentials: true
}).then(function (rs) {
console.log(rs)
}).catch(function (e) {
console.log(e)
});
}
这时候后台有几种较为常见的配置方式:
Controller
层添加注解:
使用@CorssOrigin
注解需要引入 Spring Web
的依赖,该注解可以作用于方法或者类,可以针对这个方法或类对应的一个或多个 API 配置 CORS
规则:
@RestController
@CrossOrigin
class UserController {
@GetMapping("/getUSer")
public String getUSer(String username) {
return username;
}
}
可以加在类上面,那么类下面所有的方法都支持跨域请求,如果加在方法上,仅当前方法支持。
实现 WebMvcConfigurer.addCorsMappings
方法
WebMvcConfigurer
是一个接口,它同样来自于 Spring Web
。我们可以通过实现它的 addCorsMappings
方法来针对全局 API 配置 CORS
规则:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
/**
* 跨域支持
*/
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedHeaders("*")
.allowCredentials(true)
.allowedMethods("*")
.maxAge(3600 * 24);
}
}
或者bean注入
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("*")
.allowedHeaders("*")
.allowCredentials(true)
.maxAge(3600 * 24);
}
};
}
注入 CorsFilter
CorsFilter
同样来自于 Spring Web
,但是实现 WebMvcConfigurer.addCorsMappings
方法并不会使用到这个类,具体原因我们后面来分析。我们可以通过注入一个 CorsFilter
来使用它:
@WebFilter("/getUser")
public class CorsFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse)servletResponse;
//设置允许跨域访问的服务域名,*号表示允许所有域访问
//resp.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Origin", "*");
//设置允许跨域的请求方法
response.setHeader("Access-Control-Allow-Methods", "*");
//放行
filterChain.doFilter(servletRequest, servletResponse);
}
}
或者bean注入
@Configuration
public class CORSConfiguration {
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}
这种方式较多,可以自行百度
Spring Security 中的配置
注入bean
@Bean
public CorsConfigurationSource corsConfigurationSource() {
final CorsConfiguration configuration = new CorsConfiguration();
// 预检请求的有效期,单位为秒
configuration.setMaxAge(3600L);
//允许跨域访问的域名
configuration.setAllowedOrigins(Collections.singletonList("*"));
//允许的请求方法
configuration.setAllowedMethods(Collections.singletonList("*"));
// 是否支持安全证书
configuration.setAllowCredentials(true);
//允许的请求头
configuration.setAllowedHeaders(Collections.singletonList("*"));
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
在ResourceServerConfigurerAdapter实现类中配置
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Autowired
private CorsConfigurationSource corsConfigurationSource;
@Override
public void configure(HttpSecurity http) throws Exception {
http.csrf().disable().exceptionHandling()
.authenticationEntryPoint(
(request, response, authException) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED))
.and().requestMatchers().antMatchers("/**")
.and().authorizeRequests()
.antMatchers("/user/login", "/user/logout").permitAll()
// .requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
.anyRequest().authenticated() //等同于 .antMatchers("/**").authenticated()
.and()
.httpBasic()
.and()
.cors().configurationSource(corsConfigurationSource)
;
}
}