Wir haben Spring Security
zu unserem bestehenden Projekt hinzugefügt.
Von diesem Moment an erhalten wir einen 401 No 'Access-Control-Allow-Origin' header is present on the requested resource
Fehler von unserem Server.
Das liegt daran, dass der Antwort kein Access-Control-Allow-Origin
-Header angehängt ist. Um dies zu beheben, haben wir unseren eigenen Filter hinzugefügt, der sich vor dem Logout-Filter in der Kette Filter
befindet. Der Filter gilt jedoch nicht für unsere Anfragen.
Unser Fehler:
XMLHttpRequest kann
http://localhost:8080/getKunden
nicht laden. Auf der angeforderten Ressource ist kein Header "Access-Control-Allow-Origin" vorhanden. Originhttp://localhost:3000
ist daher kein Zugriff erlaubt. Die Antwort hatte den HTTP-Statuscode 401.
Unsere Sicherheitskonfiguration:
@EnableWebSecurity
@Configuration
@ComponentScan("com.company.praktikant")
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private MyFilter filter;
@Override
public void configure(HttpSecurity http) throws Exception {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
final CorsConfiguration config = new CorsConfiguration();
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("GET");
config.addAllowedMethod("PUT");
config.addAllowedMethod("POST");
source.registerCorsConfiguration("/**", config);
http.addFilterBefore(new MyFilter(), LogoutFilter.class).authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/*").permitAll();
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
}
}
Unser Filter
@Component
public class MyFilter extends OncePerRequestFilter {
@Override
public void destroy() {
}
private String getAllowedDomainsRegex() {
return "individual / customized Regex";
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
final String Origin = "http://localhost:3000";
response.addHeader("Access-Control-Allow-Origin", Origin);
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Headers",
"content-type, x-gwt-module-base, x-gwt-permutation, clientid, longpush");
filterChain.doFilter(request, response);
}
}
Unsere anwendung
@SpringBootApplication
public class Application {
public static void main(String[] args) {
final ApplicationContext ctx = SpringApplication.run(Application.class, args);
final AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
annotationConfigApplicationContext.register(CORSConfig.class);
annotationConfigApplicationContext.refresh();
}
}
Unser Filter ist ab Springboot registriert:
2016-11-04 09: 19: 51.494 INFO 9704 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean: Zuordnungsfilter: 'myFilter' auf: [/ *]
Unsere generierte Filterkette:
2016-11-04 09: 19: 52.729 INFO 9704 --- [ost-startStop-1] ossweb.DefaultSecurityFilterChain: Erstellen einer Filterkette: [email protected]1, [org. springfrack.securi[email protected]5d8c5a8a, org.springframework.securi[email protected]7d6938f, org.springframework.security.web. [email protected], [email protected], org.[email protected]2330834f, org.springframework.security.web.savedrequest.Rach. springframework.[email protected]4fc0f1a2, org.springfram[email protected]2357120f, Exce ptionTranslationFilter @ 4b8bf1fb, org.springfr[email protected]42063cf1]
Die Antwort: Antwortheader
Wir haben die Lösung auch aus dem Frühjahr probiert, aber es hat nicht funktioniert! Die Annotation @CrossOrigin in unserem Controller hat auch nicht geholfen.
Versuchte die Lösung von @Piotr Sołtysiak. Der cors-Filter ist nicht in der generierten Filterkette aufgeführt und wir erhalten immer noch den gleichen Fehler.
2016-11-04 10: 22: 49.881 INFO 8820 --- [ost-startStop-1] ossweb.DefaultSecurityFilterChain: Erstellen einer Filterkette: [email protected]1, [org. springfrachet[email protected]4c191377, org.spring[email protected]28bad32a, org.springframework.secur.web.header.Headerrrrrrrrrrrrrrrrr. [email protected], org.[email protected]1c9cd096, org.springframework.s[email protected]3990c331, org. DefaultLoginPageGeneratingFilter @ 1e8d4ac1, org.springfram[email protected]2d61.b2a4, org.springframework.security.web.savedrequest.RequestCacheAwareFilter @ rAwareRequestFilter @ abf2de3, org.ruhringfram[email protected]2a5c161b, [email protected]5, org. [email protected]]
Übrigens verwenden wir die Federsicherheitsversion 4.1.3.!
Ok, nach über zwei Tagen der Suche haben wir das Problem behoben. Wir haben alle unsere Filter und Konfigurationen gelöscht und stattdessen diese 5 Zeilen Code in der Anwendungsklasse verwendet.
@SpringBootApplication
public class Application {
public static void main(String[] args) {
final ApplicationContext ctx = SpringApplication.run(Application.class, args);
}
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("http://localhost:3000");
}
};
}
}
Seit Spring Security 4.1 ist dies der richtige Weg, um Spring Security CORS zu unterstützen (wird auch in Spring Boot 1.4/1.5 benötigt):
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedMethods("HEAD", "GET", "PUT", "POST", "DELETE", "PATCH");
}
}
und:
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// http.csrf().disable();
http.cors();
}
@Bean
public CorsConfigurationSource corsConfigurationSource() {
final CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(ImmutableList.of("*"));
configuration.setAllowedMethods(ImmutableList.of("HEAD",
"GET", "POST", "PUT", "DELETE", "PATCH"));
// setAllowCredentials(true) is important, otherwise:
// The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
configuration.setAllowCredentials(true);
// setAllowedHeaders is important! Without it, OPTIONS preflight request
// will fail with 403 Invalid CORS request
configuration.setAllowedHeaders(ImmutableList.of("Authorization", "Cache-Control", "Content-Type"));
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
Tun Sie nichts , was der falsche Weg ist, um das Problem zu lösen:
http.authorizeRequests().antMatchers(HttpMethod.OPTIONS, "/**").permitAll();
web.ignoring().antMatchers(HttpMethod.OPTIONS);
Referenz: http://docs.spring.io/spring-security/site/docs/4.2.x/reference/html/cors.html
Da ich Probleme mit den anderen Lösungen hatte (vor allem, damit es in allen Browsern funktioniert, erkennt Edge beispielsweise "*" nicht als gültigen Wert für "Access-Control-Allow-Methods"), musste ich einen benutzerdefinierten Wert verwenden Filter Component, die am Ende für mich gearbeitet hat und genau das gemacht hat, was ich erreichen wollte.
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CorsFilter implements Filter {
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", "*");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods",
"ACL, CANCELUPLOAD, CHECKIN, CHECKOUT, COPY, DELETE, GET, HEAD, LOCK, MKCALENDAR, MKCOL, MOVE, OPTIONS, POST, PROPFIND, PROPPATCH, PUT, REPORT, SEARCH, UNCHECKOUT, UNLOCK, UPDATE, VERSION-CONTROL");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept, Key, Authorization");
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(req, res);
}
}
public void init(FilterConfig filterConfig) {
// not needed
}
public void destroy() {
//not needed
}
}
Sie brauchen nicht:
@Configuration
@ComponentScan("com.company.praktikant")
@EnableWebSecurity
enthält bereits @Configuration
, und ich kann mir nicht vorstellen, warum Sie @ComponentScan
dort ablegen.
Über den CORS-Filter würde ich nur folgendes sagen:
@Bean
public FilterRegistrationBean corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
bean.setOrder(0);
return bean;
}
In die SecurityConfiguration-Klasse und entfernen Sie globale Methoden. Sie müssen die Erlaubnis-Orgins, Header und Methoden nicht zweimal festlegen. Vor allem, wenn Sie unterschiedliche Eigenschaften in die Filter- und Federkonfigurationskonfiguration setzen :)
Laut oben ist Ihre "MyFilter" -Klasse redundant.
Sie können diese auch entfernen:
final AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
annotationConfigApplicationContext.register(CORSConfig.class);
annotationConfigApplicationContext.refresh();
Aus der Anwendungsklasse.
Am Ende kleiner Rat - nicht mit der Frage verbunden. Sie möchten keine Verben in URI einfügen. Anstelle von http://localhost:8080/getKunden
sollten Sie die HTTP-GET-Methode für http://localhost:8080/kunden
-Ressource verwenden. Best Practices für das Design von RESTful-API erfahren Sie hier: http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api
Mit Spring Security in Spring Boot 2 können Sie CORS global konfigurieren (z. B. alle Entwicklungsanforderungen aktivieren).
@Bean
protected CorsConfigurationSource corsConfigurationSource() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
return source;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors()
.and().authorizeRequests()
.anyRequest().permitAll()
.and().csrf().disable();
}
Gemäß der CORS-Filterdokumentation :
"Spring MVC bietet eine fein abgestimmte Unterstützung für die CORS-Konfiguration .__ durch Annotationen auf Controllern. Wenn jedoch mit Spring Verwendet wird, ist es ratsam, sich auf den eingebauten CorsFilter zu verlassen, der bestellt werden muss .__ vor der Filterkette von Spring Security "
So etwas erlaubt GET
den Zugriff auf den /ajaxUri
:
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import Java.util.Arrays;
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class AjaxCorsFilter extends CorsFilter {
public AjaxCorsFilter() {
super(configurationSource());
}
private static UrlBasedCorsConfigurationSource configurationSource() {
CorsConfiguration config = new CorsConfiguration();
// origins
config.addAllowedOrigin("*");
// when using ajax: withCredentials: true, we require exact Origin match
config.setAllowCredentials(true);
// headers
config.addAllowedHeader("x-requested-with");
// methods
config.addAllowedMethod(HttpMethod.OPTIONS);
config.addAllowedMethod(HttpMethod.GET);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/startAsyncAuthorize", config);
source.registerCorsConfiguration("/ajaxUri", config);
return source;
}
}
Natürlich muss Ihre SpringSecurity-Konfiguration den Zugriff auf den URI mit den aufgelisteten Methoden ermöglichen. Siehe @Hendy Irawan Antwort.
An vielen Stellen sehe ich die Antwort, die diesen Code hinzufügen muss:
@Bean
public FilterRegistrationBean corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
bean.setOrder(0);
return bean;
}
in meinem Fall löst es jedoch eine unerwartete Ausnahme vom Klassentyp aus. corsFilter()
bean benötigt den Typ CorsFilter
, also habe ich diese Änderungen vorgenommen und diese Definition von bean in meine config gesetzt. Jetzt ist alles in Ordnung.
@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);
}
In meinem Fall habe ich diese Klasse gerade hinzugefügt und @EnableAutConfiguration verwendet
package com.package.filter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.GenericFilterBean;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import Java.io.IOException;
@Component
public class SimpleCORSFilter extends GenericFilterBean {
/**
* The Logger for this class.
*/
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
logger.info("> doFilter");
HttpServletResponse response = (HttpServletResponse) resp;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type");
//response.setHeader("Access-Control-Allow-Credentials", "true");
chain.doFilter(req, resp);
logger.info("< doFilter");
}
}
Für bereits implementierte Programme, die sich Codeänderungen nicht leisten können (z. B. Federsicherheit hinzufügen/aktualisieren), ist das Hinzufügen eines einfachen Proxy eine Lösung: https://stackoverflow.com/a/49827300/1758194