wake-up-neo.com

Spring Boot Security CORS

Ich habe ein Problem mit dem CORS-Filter für Spring Security-URLs . Es wird weder Access-Control-Allow-Origin noch andere exponierte Header auf URLs gesetzt, die zu Springsek (Login/Logout) gehören oder von Spring Security gefiltert werden.

Hier sind die Konfigurationen.

KERN:

@Configuration
@EnableWebMvc
public class MyWebMvcConfig extends WebMvcConfigurerAdapter {
********some irrelevant configs************
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/*").allowedOrigins("*").allowedMethods("GET", "POST", "OPTIONS", "PUT")
                .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")
                .allowCredentials(true).maxAge(3600);
    }
}

Sicherheit:

@Configuration
@EnableWebSecurity
public class OAuth2SecurityConfiguration extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint).and()
                .formLogin()
                    .successHandler(ajaxSuccessHandler)
                    .failureHandler(ajaxFailureHandler)
                    .loginProcessingUrl("/authentication")
                    .passwordParameter("password")
                    .usernameParameter("username")
                .and()
                .logout()
                    .deleteCookies("JSESSIONID")
                    .invalidateHttpSession(true)
                    .logoutUrl("/logout")
                    .logoutSuccessUrl("/")
                .and()
                .csrf().disable()
                .anonymous().disable()
                .authorizeRequests()
                .antMatchers("/authentication").permitAll()
                .antMatchers("/oauth/token").permitAll()
                .antMatchers("/admin/*").access("hasRole('ROLE_ADMIN')")
                .antMatchers("/user/*").access("hasRole('ROLE_USER')");
    }
}

Wenn ich also eine Anfrage an die URLs stelle, die nicht von der Sicherheit abgehört werden, werden CORS-Header gesetzt. Spring-Sicherheits-URLs - nicht festgelegt.

Springstiefel 1.4.1

11
user1935987

Anstatt CorsRegistry zu verwenden, können Sie Ihren eigenen CorsFilter schreiben und zu Ihrer Sicherheitskonfiguration hinzufügen.

Benutzerdefinierte CorsFilter-Klasse:

public class CorsFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        HttpServletRequest request= (HttpServletRequest) servletRequest;

        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "GET,POST,DELETE,PUT,OPTIONS");
        response.setHeader("Access-Control-Allow-Headers", "*");
        response.setHeader("Access-Control-Allow-Credentials", true);
        response.setHeader("Access-Control-Max-Age", 180);
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {

    }
}

Sicherheitskonfigurationsklasse:

@Configuration
@EnableWebSecurity
public class OAuth2SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Bean
    CorsFilter corsFilter() {
        CorsFilter filter = new CorsFilter();
        return filter;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .addFilterBefore(corsFilter(), SessionManagementFilter.class) //adds your custom CorsFilter
                .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint).and()
                .formLogin()
                    .successHandler(ajaxSuccessHandler)
                    .failureHandler(ajaxFailureHandler)
                    .loginProcessingUrl("/authentication")
                    .passwordParameter("password")
                    .usernameParameter("username")
                .and()
                .logout()
                    .deleteCookies("JSESSIONID")
                    .invalidateHttpSession(true)
                    .logoutUrl("/logout")
                    .logoutSuccessUrl("/")
                .and()
                .csrf().disable()
                .anonymous().disable()
                .authorizeRequests()
                .antMatchers("/authentication").permitAll()
                .antMatchers("/oauth/token").permitAll()
                .antMatchers("/admin/*").access("hasRole('ROLE_ADMIN')")
                .antMatchers("/user/*").access("hasRole('ROLE_USER')");
    }
}
19
mika

Option 1 (WebMvcConfigurer Bean verwenden):

Die CORS-Konfiguration, mit der Sie begonnen haben, ist nicht die richtige Methode für Spring Boot. Sie müssen eine WebMvcConfigurer Bean registrieren. Referenz hier .

Beispiel einer Spring Boot CORS Konfiguration:

@Configuration
@Profile("dev")
public class DevConfig {

    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurerAdapter() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**").allowedOrigins("http://localhost:4200");
            }
        };
    }

}

Dadurch wird die CORS-Konfiguration für eine einfache Spring Boot-Anwendung (ohne Sicherheitsstarter) bereitgestellt. Beachten Sie, dass die CORS-Unterstützung von Spring Security unabhängig ist.

Sobald Sie Spring Security eingeführt haben, müssen Sie CORS mit Ihrer Sicherheitskonfiguration registrieren. Spring Security ist intelligent genug, um Ihre vorhandene CORS-Konfiguration zu übernehmen.

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .cors().and()              
         ....

Option 2 (CorsConfigurationSource Bean verwenden):

Die erste Option, die ich beschrieben habe, bezieht sich auf das Hinzufügen von Spring Security zu einer vorhandenen Anwendung. Wenn Sie Spring Security von Anfang an hinzufügen, wird in den Spring Security Docs eine CorsConfigurationSource-Bean hinzugefügt.

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            // by default uses a Bean by the name of corsConfigurationSource
            .cors().and()
            ...
    }

    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("https://example.com"));
        configuration.setAllowedMethods(Arrays.asList("GET","POST"));
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
}

Ich habe einen React-basierten Web-Client, und meine Backend-API REST führt Spring Boot Ver 1.5.2 aus

Ich wollte schnell CORS für alle Controller-Routenanfragen meines Clients aktivieren, der unter localhost:8080 ausgeführt wird. In meiner Sicherheitskonfiguration habe ich einfach einen @Bean vom Typ FilterRegistrationBean hinzugefügt und es funktioniert problemlos. 

Hier ist der Code:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class AuthConfiguration extends WebSecurityConfigurerAdapter {

....
....

  @Bean
  public FilterRegistrationBean corsFilter() {
    final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowCredentials(true);
    config.addAllowedOrigin(corsAllowedOrigin); // @Value: http://localhost:8080
    config.addAllowedHeader("*");
    config.addAllowedMethod("*");
    source.registerCorsConfiguration("/**", config);
    FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
    bean.setOrder(0);
    return bean;
  }

  @Override
  protected void configure(HttpSecurity httpSecurity) throws Exception {    
      httpSecurity
        .authorizeRequests()
        .antMatchers(HttpMethod.OPTIONS, "/**").permitAll() // **permit OPTIONS call to all**
        ....
  }

....
....

}

Sie können Spring Boot docs hier beziehen

2
sisanared

Wenn Sie es für eine schnelle lokale Entwicklung benötigen, fügen Sie diese Anmerkung einfach auf Ihrem Controller hinzu. (Herkunft natürlich ändern)

@CrossOrigin(origins = "http://localhost:4200", maxAge = 3600)
1
Neeraj

Ich hatte gerade ein ähnliches Problem. Ich habe versucht, eine Anforderung von meinem Frontend in React executing on http: // localhost: 30 an mein Backend in SpringBoot auszuführen Ausführung um http: // localhost: 808 . Ich hatte zwei Fehler:

Zugriffskontrolle Ursprung zulassen

Ich habe das sehr einfach gelöst, indem ich dies meinem RestController hinzufügte:

@CrossOrigin(origins = ["http://localhost:3000"])

Nachdem ich das behoben hatte, bekam ich folgende Fehlermeldung: Der Wert des Headers 'Access-Control-Allow-Credentials' in der Antwort ist '', was 'true' sein muss

Zugriffssteuerung-Berechtigungsnachweise zulassen

Dieser kann auf zwei Arten umgangen werden:

  1. Hinzufügen von allowCredentials = "true" Zur CrossOrigin-Konfiguration:

    @CrossOrigin(origins = ["http://localhost:3000"], allowCredentials = "true")

  2. Ändern der Anmeldeinformationsoptionen des Abrufs in der Frontend-Anforderung. Grundsätzlich müssen Sie den Abrufaufruf wie folgt ausführen:

    fetch('http://localhost:8080/your/api', { credentials: 'same-Origin' })

Hoffe das hilft =)

Sie könnten dies auch mit einem Interceptor erreichen.

Verwenden Sie die Ausnahme, um sicherzustellen, dass Sie den Lebenszyklus der Anforderung beenden:

@ResponseStatus (
    value = HttpStatus.NO_CONTENT
)
public class CorsException extends RuntimeException
{
}

Setzen Sie dann in Ihrem Interceptor Header für alle OPTIONS-Anforderungen und geben Sie die Ausnahme aus:

public class CorsMiddleware extends HandlerInterceptorAdapter
{
    @Override
    public boolean preHandle (
        HttpServletRequest request,
        HttpServletResponse response,
        Object handler
    ) throws Exception
    {
        if (request.getMethod().equals("OPTIONS")) {
            response.addHeader("Access-Control-Allow-Origin", "*");
            response.addHeader("Access-Control-Allow-Credentials", "true");
            response.addHeader("Access-Control-Allow-Methods","GET, POST, PUT, OPTIONS, DELETE");
            response.addHeader("Access-Control-Allow-Headers", "DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,Authorization,If-Modified-Since,Cache-Control,Content-Type");
            response.addHeader("Access-Control-Max-Age", "3600");
            response.addHeader("charset", "utf-8");
            throw new CorsException();
        }

        return super.preHandle(request, response, handler);
    }
}

Wenden Sie den Interceptor schließlich auf alle Routen an:

@Configuration
public class MiddlewareConfig extends WebMvcConfigurerAdapter
{
    @Override
    public void addInterceptors (InterceptorRegistry registry)
    {
        registry.addInterceptor(new CorsMiddleware())
                .addPathPatterns("/**");
    }
}
1

Derzeit werden die OPTIONS-Anforderungen standardmäßig blockiert, wenn die Sicherheit aktiviert ist.

Fügen Sie einfach eine zusätzliche Bean hinzu, und Preflight-Anforderungen werden korrekt verarbeitet:

   @Bean
   public IgnoredRequestCustomizer optionsIgnoredRequestsCustomizer() {
      return configurer -> {
         List<RequestMatcher> matchers = new ArrayList<>();
         matchers.add(new AntPathRequestMatcher("/**", "OPTIONS"));
         configurer.requestMatchers(new OrRequestMatcher(matchers));
      };
   }

Bitte beachten Sie, dass dies je nach Anwendung für potenzielle Exploits möglich ist.

Eröffnete Ausgabe für eine bessere Lösung: https://github.com/spring-projects/spring-security/issues/4448

0