【发布时间】:2019-01-19 21:42:04
【问题描述】:
我正在尝试使用 Angular 实现文件上传。 Angular 托管在具有此代理模块配置的 Apache 服务器上:
<Directory /var/www/html/admin>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
<IfModule mod_proxy.c>
ProxyRequests Off
ProxyVia Off
ProxyPreserveHost On
ProxyStatus On
ProxyPass /api_admin http://localhost:8080/api_admin
ProxyPassReverse /api_admin http://localhost:8080/api_admin
ProxyPassReverseCookiePath /api_admin /
</IfModule>
我使用此配置将 Angular 应用程序托管在 Apache 的子目录下:
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteBase /admin/
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} !-f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^(.*) index.html [NC,L]
</IfModule>
文件上传的打字稿代码:
imports (file: any) {
const url = `http://111.111.111/api_admin/merchants/upload`;
const formData = new FormData();
formData.append('file', file, file.name);
return this.http.post(url, formData);
}
Spring 端点:
@RestController
@RequestMapping("/merchants")
public class MerchantController {
@PostMapping("/upload")
public ResponseEntity<String> uploadData(@RequestParam("file") MultipartFile file) throws Exception {
.........
}
}
Spring 安全配置:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private DbUserDetailsService dbuserDetailsService;
@Autowired
private PasswordEncoder passwordEncoder;
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
public UserDetailsService userDetailsServiceBean() throws Exception {
return dbuserDetailsService;
}
@Override
protected UserDetailsService userDetailsService() {
return dbuserDetailsService;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(dbuserDetailsService)
.passwordEncoder(passwordEncoder);
}
@Autowired
public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(dbuserDetailsService)
.passwordEncoder(passwordEncoder);
}
}
路径:
@Configuration
@EnableResourceServer
public class ResourceSecurityConfig extends ResourceServerConfigurerAdapter {
@Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.resourceId("resource_id").stateless(true);
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/users/**").permitAll()
.anyRequest().authenticated();
}
}
但我收到 CORS 错误。通常我可以打开所有页面并向 BE 发出请求,但只有这个文件上传不起作用。我试过这个:
@CrossOrigin(origins = "*", methods = {RequestMethod.POST, RequestMethod.OPTIONS}, allowedHeaders = {"Content-Type", "X-Requested-With", "accept", "Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers"}, exposedHeaders = {"Access-Control-Allow-Origin", "Access-Control-Allow-Credentials"})
@PostMapping("/upload")
public ResponseEntity<String> uploadData(@RequestParam("file") MultipartFile file) throws Exception {
.........
}
但上传请求再次被 CORS 阻止。
您知道如何配置 Apache mod_rewrite 以正确重定向流量吗?
我尝试的第二种方法:
@Configuration
@EnableResourceServer
public class ResourceSecurityConfig extends ResourceServerConfigurerAdapter {
@Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.resourceId("resource_id").stateless(true);
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/users/**").permitAll()
.anyRequest().authenticated()
.and()
.cors().disable()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.anyRequest()
.fullyAuthenticated()
.and()
.httpBasic()
.and()
.csrf().disable();
}
@Bean
public CorsConfigurationSource corsConfigurationSources() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("*"));
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"));
configuration.setAllowedHeaders(Arrays.asList("authorization", "content-type", "x-auth-token"));
configuration.setExposedHeaders(Arrays.asList("x-auth-token"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
第二个配置我得到has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.
auth:1 Failed to load resource: the server responded with a status of 404 (Not Found)
实现此结果的最佳方法是什么?
有没有办法在不禁用 CORS 的情况下实现这一点?
【问题讨论】:
-
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin")); - 这是一个非常非常糟糕的主意。特别是在全局过滤器中,因为它基本上完全禁用了任何 CORS 检查。另外:预检请求实际上返回了什么?您应该能够在您的客户中看到这一点。您引用的错误消息只是后续内容。
-
我找不到更多调试信息。在 Chrome 中哪里可以看到?
-
在“网络”选项卡上的开发人员工具中。如果启用“方法”列,则更容易发现 OPTIONS 请求
-
这是选项。看到这个:ibb.co/bP9hr8S
-
如您所见,状态为“401”......这意味着,有人正在发回“身份验证”相关的返回状态。唯一会这样做的是弹簧安全。您在这里拥有的过滤器介于两者之间 - 如果您对实际的 CORS 感兴趣(您应该,它更安全),那么您需要检查弹簧安全性在做什么。否则,您可以只处理 apache 中的所有 OPTIONS 请求,准确返回您在过滤器中所做的事情,甚至不将其传递给 BE。
标签: spring spring-boot spring-mvc cors mod-proxy