CORS com bota de mola e angularjs não funciona

87

Estou tentando chamar pontos de extremidade REST em um aplicativo (aplicativo de inicialização rápida) de outro (angularjs). Os aplicativos estão sendo executados nos seguintes hosts e portas.

  • Aplicação REST, usando boot de mola, http://localhost:8080
  • Aplicativo HTML, usando angularjs, http://localhost:50029

Também estou usando spring-securitycom o aplicativo Spring Boot. A partir do aplicativo HTML, posso autenticar no aplicativo REST, mas, depois disso, ainda não consigo acessar nenhum terminal REST. Por exemplo, eu tenho um serviço angularjs definido como segue.

adminServices.factory('AdminService', ['$resource', '$http', 'conf', function($resource, $http, conf) {
    var s = {};
    s.isAdminLoggedIn = function(data) {
        return $http({
            method: 'GET',
            url: 'http://localhost:8080/api/admin/isloggedin',
            withCredentials: true,
            headers: {
                'X-Requested-With': 'XMLHttpRequest'
            }
        });
    };
    s.login = function(username, password) {
        var u = 'username=' + encodeURI(username);
        var p = 'password=' + encodeURI(password);
        var r = 'remember_me=1';
        var data = u + '&' + p + '&' + r;

        return $http({
            method: 'POST',
            url: 'http://localhost:8080/login',
            data: data,
            headers: {'Content-Type': 'application/x-www-form-urlencoded'}
        });
    };
    return s;
}]);

O controlador angularjs se parece com o seguinte.

adminControllers.controller('LoginController', ['$scope', '$http', 'AdminService', function($scope, $http, AdminService) {
    $scope.username = '';
    $scope.password = '';

    $scope.signIn = function() {
        AdminService.login($scope.username, $scope.password)
            .success(function(d,s) {
                if(d['success']) {
                    console.log('ok authenticated, call another REST endpoint');
                    AdminService.isAdminLoggedIn()
                        .success(function(d,s) {
                            console.log('i can access a protected REST endpoint after logging in');
                        })
                        .error(function(d, s) { 
                            console.log('huh, error checking to see if admin is logged in');
                            $scope.reset();
                        });
                } else {
                    console.log('bad credentials?');
                }
            })
            .error(function(d, s) {
                console.log('huh, error happened!');
            });
    };
}]);

Na ligação para http://localhost:8080/api/admin/isloggedin, recebo um 401 Unauthorized.

No lado do aplicativo REST, tenho um filtro CORS parecido com o seguinte.

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CORSFilter implements Filter {

    @Override
    public void destroy() { }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        HttpServletRequest request = (HttpServletRequest) req;

        response.setHeader("Access-Control-Allow-Origin", "http://localhost:50029");
        response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "X-Requested-With, X-Auth-Token");
        response.setHeader("Access-Control-Allow-Credentials", "true");

        if(!"OPTIONS".equalsIgnoreCase(request.getMethod())) {
            chain.doFilter(req, res);
        }
    }

    @Override
    public void init(FilterConfig config) throws ServletException { }
}

Minha configuração de segurança de primavera se parece com o seguinte.

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private RestAuthenticationEntryPoint restAuthenticationEntryPoint;

    @Autowired
    private JsonAuthSuccessHandler jsonAuthSuccessHandler;

    @Autowired
    private JsonAuthFailureHandler jsonAuthFailureHandler;

    @Autowired
    private JsonLogoutSuccessHandler jsonLogoutSuccessHandler;

    @Autowired
    private AuthenticationProvider authenticationProvider;

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private PersistentTokenRepository persistentTokenRepository;

    @Value("${rememberme.key}")
    private String rememberMeKey;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            .exceptionHandling()
            .authenticationEntryPoint(restAuthenticationEntryPoint)
                .and()
            .authorizeRequests()
                .antMatchers("/api/admin/**").hasRole("ADMIN")
                .antMatchers("/", "/admin", "/css/**", "/js/**", "/fonts/**", "/api/**").permitAll()
                .anyRequest().authenticated()
                .and()
            .formLogin()
                .successHandler(jsonAuthSuccessHandler)
                .failureHandler(jsonAuthFailureHandler)
                .permitAll()
                .and()
            .logout()
                .deleteCookies("remember-me", "JSESSIONID")
                .logoutSuccessHandler(jsonLogoutSuccessHandler)
                .permitAll()
                .and()
            .rememberMe()
                .userDetailsService(userDetailsService)
                .tokenRepository(persistentTokenRepository)
                .rememberMeCookieName("REMEMBER_ME")
                .rememberMeParameter("remember_me")
                .tokenValiditySeconds(1209600)
                .useSecureCookie(false)
                .key(rememberMeKey);
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .authenticationProvider(authenticationProvider);
    }
}

Tudo o que os manipuladores estão fazendo é escrever uma resposta JSON, como {success: true}se o usuário efetuou login, falhou na autenticação ou desconectou-se. oRestAuthenticationEntryPoint parece com o seguinte.

@Component
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {

    @Override
    public void commence(HttpServletRequest req, HttpServletResponse resp, AuthenticationException ex)
            throws IOException, ServletException {
        resp.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
    }

}

Alguma ideia do que estou perdendo ou fazendo de errado?

Jane Wayne
fonte
Suponho que você precise carregar a autenticação também, como um token ou algo assim. Você tem 2 servidores. Você olhou para aquele tutorial? spring.io/guides/tutorials/spring-security-and-angular-js
Gokhan Oner
@GokhanOner Como carrego a autenticação? Essa é provavelmente a peça que faltava para este problema. Além disso, sim, eu passei por esses tutoriais e não achei que estivessem alinhados com a minha abordagem. As duas primeiras partes trataram da autenticação Http-Basic, a terceira tratou do Redis (eu não queria ou planejava obter isso como uma dependência) e, em seguida, o último tutorial foi sobre o API Gatewaycom o spring cloud, o que achei um exagero .
Jane Wayne
Acho que você pode fazer isso sem o redis, é apenas um armazenamento de cache de valor-chave. Você precisa armazenar a autenticação e o token CSRF em uma loja, possível dentro do mapa imediatamente. O principal aqui é a chave de autenticação. veja o exemplo: github.com/dsyer/spring-security-angular/tree/master/… e a página com "servidor de recursos". Você verá alguns beans adicionais definidos, a ordem do filtro CORS também é importante. E algum suporte. mudanças também são necessárias.
Gokhan Oner
Ok, fiz uma pesquisa rápida. Tudo o que você precisa, para se livrar do Redis, é criar um bean springSessionRepositoryFilter, olhar github.com/spring-projects/spring-session/blob/1.0.0.RC1/… , e também bean sessionRepository e neste bean, em vez de RedisOperationsSessionRepository, você pode usar MapSessionRepository, que também está em spring-session. E então siga o exemplo.
Gokhan Oner

Respostas:

102
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
public class SimpleCORSFilter implements Filter {

private final Logger log = LoggerFactory.getLogger(SimpleCORSFilter.class);

public SimpleCORSFilter() {
    log.info("SimpleCORSFilter init");
}

@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {

    HttpServletRequest request = (HttpServletRequest) req;
    HttpServletResponse response = (HttpServletResponse) res;

    response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
    response.setHeader("Access-Control-Allow-Credentials", "true");
    response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
    response.setHeader("Access-Control-Max-Age", "3600");
    response.setHeader("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With, remember-me");

    chain.doFilter(req, res);
}

@Override
public void init(FilterConfig filterConfig) {
}

@Override
public void destroy() {
}

}

Não há necessidade de definir este filtro extra, basta adicionar esta classe. O Spring será digitalizado e adicionado para você. SimpleCORSFilter. Aqui está o exemplo: spring-enable-cors

abosancico
fonte
Algumas questões. 1) Onde devo colocar as constantes de string HEADERSe X_REDIRECT_LOCATION_HEADER? 2) A linha é request.getRequestURL());um erro de digitação ou erro de copiar / colar? 3) Por que você não verifica OPTIONSe simplesmente continua com a cadeia de filtros?
Jane Wayne
2
Mas bloqueia para executar AuthenticationEntryPoint .. Guia
Pra_A
1
Muito obrigado, isso me ajudou muito na minha luta para fazer a primavera e a brasa funcionarem juntas. Saúde, companheiro!
Tomasz Szymanek
FindBugs não gosta de definir um parâmetro de cabeçalho com: request.getHeader("Origin")como mostrado acima por causa da divisão de resposta HTTP
Glenn
3
Se houver outros filtros em seu aplicativo, esse filtro precisa ter a maior precedência, anotando o filtro com @Order(Ordered.HIGHEST_PRECEDENCE) .
Shafiul
43

Eu já havia passado por uma situação semelhante. Depois de fazer pesquisas e testes, aqui estão minhas descobertas:

  1. Com o Spring Boot, a maneira recomendada de habilitar CORS global é declarar dentro do Spring MVC e combinado com @CrossOriginconfiguração refinada como:

    @Configuration
    public class CorsConfig {
    
        @Bean
        public WebMvcConfigurer corsConfigurer() {
            return new WebMvcConfigurerAdapter() {
                @Override
                public void addCorsMappings(CorsRegistry registry) {
                    registry.addMapping("/**").allowedMethods("GET", "POST", "PUT", "DELETE").allowedOrigins("*")
                            .allowedHeaders("*");
                }
            };
        }
    }
    
  2. Agora, como você está usando o Spring Security, é necessário habilitar o CORS no nível do Spring Security também para permitir que ele aproveite a configuração definida no nível do Spring MVC como:

    @EnableWebSecurity
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.cors().and()...
        }
    }
    

    Aqui está um excelente tutorial que explica o suporte CORS na estrutura Spring MVC.

Yogen Rai
fonte
3
ups funciona com esta mudança http .csrf () .disable () .cors () .and ()
marti_
1
@Osgux bom saber disso :) já que estou usando JWT para autorização e eles são csrf seguros, não coloquei isso lá .. não se esqueça de votar a favor se ajudar :)
Yogen Rai
Sim, adicionei +1 = D
marti_
@Marcel, qual problema você está tendo?
Yogen Rai
Falha ao carregar <meu endereço restante>: A resposta à solicitação de comprovação não passa na verificação de controle de acesso: Nenhum cabeçalho 'Access-Control-Allow-Origin' está presente no recurso solicitado. Origem ' localhost: 8090 ', portanto, não tem acesso permitido.
Marcel
22

Se você deseja ativar o CORS sem usar filtros ou sem arquivo de configuração, basta adicionar

@CrossOrigin

na parte superior do seu controlador e funcionará.

Eduardo dennis
fonte
4
Quais são os riscos de segurança ao seguir essa abordagem?
Balaji Vignesh
Funcionou para mim, tentei adicionar cabeçalhos diretamente à resposta, mas não funcionou, pois o preflight não foi tratado. Acho que isso não é seguro, mas pode ser usado em alguns aplicativos internos.
amisiuryk
Funcionou para mim. solução bastante útil para aplicação interna.
Ajay Kumar de
8

Para construir sobre outras respostas acima, no caso de você ter um aplicativo de serviço REST Spring boot (não Spring MVC) com segurança Spring, então habilitar CORS via segurança Spring é suficiente (se você usar Spring MVC, então usando um WebMvcConfigurer bean como mencionado por Yogen pode ser o caminho a seguir, pois a segurança do Spring delegará à definição CORS mencionada nele)

Portanto, você precisa ter uma configuração de segurança que faça o seguinte:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Override
protected void configure(HttpSecurity http) throws Exception {
    //other http security config
    http.cors().configurationSource(corsConfigurationSource());
}

//This can be customized as required
CorsConfigurationSource corsConfigurationSource() {
    CorsConfiguration configuration = new CorsConfiguration();
    List<String> allowOrigins = Arrays.asList("*");
    configuration.setAllowedOrigins(allowOrigins);
    configuration.setAllowedMethods(singletonList("*"));
    configuration.setAllowedHeaders(singletonList("*"));
    //in case authentication is enabled this flag MUST be set, otherwise CORS requests will fail
    configuration.setAllowCredentials(true);
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", configuration);
    return source;
}

}

Este link contém mais informações sobre o mesmo: https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#cors

Nota:

  1. Habilitar CORS para todas as origens (*) para um aplicativo implantado prod nem sempre é uma boa ideia.
  2. CSRF pode ser habilitado por meio da personalização Spring HttpSecurity sem problemas
  3. No caso de você ter a autenticação habilitada no aplicativo com Spring (via um, UserDetailsServicepor exemplo), então o configuration.setAllowCredentials(true);deve ser adicionado

Testado para Spring boot 2.0.0.RELEASE (ou seja, Spring 5.0.4.RELEASE e Spring security 5.0.3.RELEASE)

Deepak
fonte
Isso resolveu meu problema. Sendo novo no Spring e Spring Boot, percebi que não estava construindo com Sring MVC. Eu tinha um cliente Vue.js. Outras respostas pareciam ser para Spring MVC, mas essa resposta se encaixou perfeitamente com minha autenticação e autorização já implementadas.
jaletechs
Olá @jaletechs, também estou usando nuxtJs (uma estrutura vuejs), mas quando se trata de definir o cookie, não está funcionando. você faria a gentileza de ajudar nisso.
KAmit
6

Estou usando spring boot 2.1.0e o que funcionou para mim foi

A. Adicione mapeamentos de cors por:

@Configuration
public class Config implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**").allowedOrigins("*");
    }
}

B. Adicione a configuração abaixo ao meu HttpSecuritypara segurança de primavera

.cors().configurationSource(new CorsConfigurationSource() {

    @Override
    public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowedHeaders(Collections.singletonList("*"));
        config.setAllowedMethods(Collections.singletonList("*"));
        config.addAllowedOrigin("*");
        config.setAllowCredentials(true);
        return config;
    }
})

Também no caso de um proxy Zuul você pode usar este em vez de A e B (apenas use HttpSecurity.cors()para habilitá-lo na segurança do Spring):

@Bean
public CorsFilter corsFilter() {
    final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    final CorsConfiguration config = new CorsConfiguration();
    config.setAllowCredentials(true);
    config.addAllowedOrigin("*");
    config.addAllowedHeader("*");
    config.addAllowedMethod("OPTIONS");
    config.addAllowedMethod("HEAD");
    config.addAllowedMethod("GET");
    config.addAllowedMethod("PUT");
    config.addAllowedMethod("POST");
    config.addAllowedMethod("DELETE");
    config.addAllowedMethod("PATCH");
    source.registerCorsConfiguration("/**", config);
    return new CorsFilter(source);
}
Set GH
fonte
retornar novo CorsFilter (fonte); não é esse erro do construtor
Aadam
@Aadam Você está usando a mesma versão de bota primavera que eu?
Set GH
2.1.5 está em uso
Aadam
@Aadam Esse pode ser o motivo, infelizmente.
Set GH
@Aadam Certifique-se de usar o CorsFilter do org.springframework.web.filter.CorsFilter. Eu tive o mesmo problema enquanto usava de pacotes Catalina acidentalmente.
Set GH
5

Isso funciona para mim:

@Configuration
public class MyConfig extends WebSecurityConfigurerAdapter  {
   //...
   @Override
   protected void configure(HttpSecurity http) throws Exception {

       //...         

       http.cors().configurationSource(new CorsConfigurationSource() {

        @Override
        public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
            CorsConfiguration config = new CorsConfiguration();
            config.setAllowedHeaders(Collections.singletonList("*"));
            config.setAllowedMethods(Collections.singletonList("*"));
            config.addAllowedOrigin("*");
            config.setAllowCredentials(true);
            return config;
        }
      });

      //...

   }

   //...

}
Renan Polisciuc
fonte
Embora este código possa responder à pergunta, fornecer contexto adicional sobre por que e / ou como este código responde à pergunta melhora seu valor a longo prazo.
Adriano Martins
1
Caso a autenticação seja habilitada por meio de segurança Spring, o config.setAllowCredentials (true); DEVE ser colocado, caso contrário, as solicitações CORS ainda falharão
Deepak
2

Para mim, a única coisa que funcionou 100% quando a segurança da mola é usada foi pular toda a penugem adicional de filtros e grãos extras e qualquer "mágica" indireta que as pessoas continuaram sugerindo que funcionava para eles, mas não para mim.

Em vez disso, apenas force-o a escrever os cabeçalhos de que você precisa com um simples StaticHeadersWriter:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

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

        http
            // your security config here
            .authorizeRequests()
            .antMatchers(HttpMethod.TRACE, "/**").denyAll()
            .antMatchers("/admin/**").authenticated()
            .anyRequest().permitAll()
            .and().httpBasic()
            .and().headers().frameOptions().disable()
            .and().csrf().disable()
            .headers()
            // the headers you want here. This solved all my CORS problems! 
            .addHeaderWriter(new StaticHeadersWriter("Access-Control-Allow-Origin", "*"))
            .addHeaderWriter(new StaticHeadersWriter("Access-Control-Allow-Methods", "POST, GET"))
            .addHeaderWriter(new StaticHeadersWriter("Access-Control-Max-Age", "3600"))
            .addHeaderWriter(new StaticHeadersWriter("Access-Control-Allow-Credentials", "true"))
            .addHeaderWriter(new StaticHeadersWriter("Access-Control-Allow-Headers", "Origin,Accept,X-Requested-With,Content-Type,Access-Control-Request-Method,Access-Control-Request-Headers,Authorization"));
    }
}

Esta é a maneira mais direta e explícita que encontrei de fazer isso. Espero que ajude alguém.

Jeronimo Backes
fonte
1

Passo 1

Ao anotar o controlador com @CrossOriginanotação permitirá as configurações do CORS.

@CrossOrigin
@RestController
public class SampleController { 
  .....
}

Passo 2

O Spring já tem um CorsFilter, embora você possa simplesmente registrar seu próprio CorsFilter como um bean para fornecer sua própria configuração da seguinte maneira.

@Bean
public CorsFilter corsFilter() {
    final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    final CorsConfiguration config = new CorsConfiguration();
    config.setAllowedOrigins(Collections.singletonList("http://localhost:3000")); // Provide list of origins if you want multiple origins
    config.setAllowedHeaders(Arrays.asList("Origin", "Content-Type", "Accept"));
    config.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "OPTIONS", "DELETE", "PATCH"));
    config.setAllowCredentials(true);
    source.registerCorsConfiguration("/**", config);
    return new CorsFilter(source);
}
Saveendra Ekanayake
fonte
0

verifique este:

@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
    ...
            .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
    ...
}
Yibourkelidrissi
fonte
Embora este código possa responder à pergunta, fornecer contexto adicional sobre por que e / ou como este código responde à pergunta melhora seu valor a longo prazo.
rollstuhlfahrer
0

Estender a classe WebSecurityConfigurerAdapter e substituir o método configure () em sua classe @EnableWebSecurity funcionaria: Abaixo está um exemplo de classe

@Override
protected void configure(final HttpSecurity http) throws Exception {

         http
        .csrf().disable()
        .exceptionHandling();
         http.headers().cacheControl();

        @Override
        public CorsConfiguration getCorsConfiguration(final HttpServletRequest request) {
            return new CorsConfiguration().applyPermitDefaultValues();
        }
    });
   }
}
keyRen
fonte
0

Se originalmente o seu programa não usa a segurança spring e não pode se permitir uma mudança de código, criar um proxy reverso simples pode resolver o problema. No meu caso, usei o Nginx com a seguinte configuração:

http {
  server {
    listen 9090;
    location / {
      if ($request_method = 'OPTIONS') {
      add_header 'Access-Control-Allow-Origin' '*';
      add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
      #
      # Custom headers and headers various browsers *should* be OK with but aren't
      #
      add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
      #
      # Tell client that this pre-flight info is valid for 20 days
      #
      add_header 'Access-Control-Max-Age' 1728000;
      add_header 'Content-Type' 'text/plain; charset=utf-8';
      add_header 'Content-Length' 0;
      return 204;
      }
      if ($request_method = 'POST') {
      add_header 'Access-Control-Allow-Origin' '*';
      add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
      add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
      add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
      }
      if ($request_method = 'GET') {
      add_header 'Access-Control-Allow-Origin' '*';
      add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
      add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
      add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
      }

      proxy_pass http://localhost:8080;
    }
  }
}

Meu programa escuta : 8080 .

REF: CORS em Nginx

Orvyl
fonte
0

Isto é o que funcionou para mim.

@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

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

        http.cors();
    }

}

@Configuration
public class WebConfiguration implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry
            .addMapping("/**")
            .allowedMethods("*")
            .allowedHeaders("*")
            .allowedOrigins("*")
            .allowCredentials(true);
    }

}
Dennis Crissman II
fonte
0

Esta resposta copia a resposta @abosancic, mas adiciona segurança extra para evitar exploit CORS .

Dica 1: não reflita a origem de entrada como está, sem verificar a lista de hosts permitidos para acesso.

Dica 2: permitir solicitações credenciadas apenas para hosts na lista de permissões.

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
public class SimpleCORSFilter implements Filter {

    private final Logger log = LoggerFactory.getLogger(SimpleCORSFilter.class);

    private List<String> allowedOrigins;

    public SimpleCORSFilter() {
        log.info("SimpleCORSFilter init");
        allowedOrigins = new ArrayList<>();
        allowedOrigins.add("https://mysafeorigin.com");
        allowedOrigins.add("https://itrustthissite.com");
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;

        String allowedOrigin = getOriginToAllow(request.getHeader("Origin"));

        if(allowedOrigin != null) {
            response.setHeader("Access-Control-Allow-Origin", allowedOrigin);
            response.setHeader("Access-Control-Allow-Credentials", "true");
        }

        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With, remember-me");

        chain.doFilter(req, res);
    }

    @Override
    public void init(FilterConfig filterConfig) {
    }

    @Override
    public void destroy() {
    }

    public String getOriginToAllow(String incomingOrigin) {
        if(allowedOrigins.contains(incomingOrigin.toLowerCase())) {
            return incomingOrigin;
        } else {
            return null;
        }
    }
}
Shailesh Pratapwar
fonte
0

Em nosso aplicativo Spring Boot, configuramos CorsConfigurationSource assim.

A sequência de adição allowedOrignsprimeiro e depois configuração applyPermitDefaultValues()permite que o Spring configure os valores padrão para cabeçalhos permitidos, cabeçalhos expostos, métodos permitidos, etc., então não temos que especificá-los.

    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("http://localhost:8084"));
        configuration.applyPermitDefaultValues();

        UrlBasedCorsConfigurationSource configurationSource = new UrlBasedCorsConfigurationSource();
        configurationSource.registerCorsConfiguration("/**", configuration);
        return configurationSource;
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.authorizeRequests()
                .antMatchers("/api/**")
                .access("@authProvider.validateApiKey(request)")
                .anyRequest().authenticated()
                .and().cors()
                .and().csrf().disable()
                .httpBasic().authenticationEntryPoint(authenticationEntryPoint);

        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }
Conheça Shah
fonte
0

Basta fazer uma única classe como, tudo ficará bem com isso:

        @Component
        @Order(Ordered.HIGHEST_PRECEDENCE)
        public class MyCorsConfig implements Filter {

            @Override
            public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
                final HttpServletResponse response = (HttpServletResponse) res;
                response.setHeader("Access-Control-Allow-Origin", "*");
                response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
                response.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type, enctype");
                response.setHeader("Access-Control-Max-Age", "3600");
                if (HttpMethod.OPTIONS.name().equalsIgnoreCase(((HttpServletRequest) req).getMethod())) {
                    response.setStatus(HttpServletResponse.SC_OK);
                } else {
                    chain.doFilter(req, res);
                }
            }

            @Override
            public void destroy() {
            }

            @Override
            public void init(FilterConfig config) throws ServletException {
            }
        }
Imranmadbar
fonte
0

Isso é o que funcionou para mim, a fim de desabilitar o CORS entre o Spring boot e React

@Configuration
public class CorsConfig implements WebMvcConfigurer {

    /**
     * Overriding the CORS configuration to exposed required header for ussd to work
     *
     * @param registry CorsRegistry
     */

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowedMethods("*")
                .allowedHeaders("*")
                .allowCredentials(true)
                .maxAge(4800);
    }
}

Tive que modificar a configuração de Segurança também como abaixo:

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.csrf().disable()
                    .cors().configurationSource(new CorsConfigurationSource() {

                @Override
                public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
                    CorsConfiguration config = new CorsConfiguration();
                    config.setAllowedHeaders(Collections.singletonList("*"));
                    config.setAllowedMethods(Collections.singletonList("*"));
                    config.addAllowedOrigin("*");
                    config.setAllowCredentials(true);
                    return config;
                }
            }).and()
                    .antMatcher("/api/**")
                    .authorizeRequests()
                    .anyRequest().authenticated()
                    .and().httpBasic()
                    .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                    .and().exceptionHandling().accessDeniedHandler(apiAccessDeniedHandler());
        }
Gil Nz
fonte