【问题标题】:Upload file from angular to Spring without configuring CORS在不配置 CORS 的情况下将文件从 Angular 上传到 Spring
【发布时间】: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


【解决方案1】:

几个cmets:

  1. 要解决您的问题,您应该使用response.setStatus(200);
  2. 您当前的实现不使用 Spring。它使用 Java 过滤器。 Spring 内置了 CORS 处理工具,例如见this
  3. 由于您接受所有来源,因此您当前的实现不安全并且容易受到“CORS 攻击”。这允许攻击者代表您的用户执行操作并读取他们的个人信息。为防止这种情况,您应该检查来源是否与您的来源白名单匹配

【讨论】:

  • 谢谢,我添加了第二次尝试,但我再次遇到同样的错误。你知道我该如何解决吗?
  • 完全相同的错误?您是否从代码中删除了过滤器?
  • 是的,我做到了。我也不知道为什么会出现此错误。
  • 这是否与我的设置有关 - 我使用托管在 Apache 服务器上的 Angular 6 FE 和 Wildfly 服务器上的 Spring BE。你知道还需要做一些 apache 或 Wildfly 配置吗?
【解决方案2】:

您已通过配置 .cors().disable() 在 ResourceSecurityConfig 中禁用跨源资源共享。尝试删除disable() 部分并保留.cors() 部分。这将在应用程序的安全部分启用 CORS,并使其在预检请求中返回 OK 状态。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-03
    • 2017-05-02
    • 2020-03-12
    • 2014-12-05
    • 2016-03-12
    • 1970-01-01
    • 2019-04-25
    相关资源
    最近更新 更多