Angular / Spring Boot mit Keycloak wirft 403
Ich habe meine Spring Boot-Anwendung mit Keycloak 11.0.2 und Spring Security gemäß dieser Dokumentation gesichert .
Ich habe die grundlegende Keycloak-Konfiguration verwendet in application.properties:
keycloak.auth-server-url=http://localhost:8085/auth
keycloak.realm=cirta
keycloak.resource=cirta-api
keycloak.public-client=false
Ich habe eine separate Frontend-Angular-App, die in Keylocak als anderer Client konfiguriert ist. aber im gleichen Bereich wie die Spring Boot App. Über die Angular-App sende ich das von Keycloak bereitgestellte Token in den HTTP-Headern mit:
'Authorization' : 'Bearer ' + this.securityService.kc.token
Wenn ich auf eine Angular-Seite zugreife, die eine GETAPI aufruft , wird folgende blocked by CORS policyFehlermeldung angezeigt:
Access to XMLHttpRequest at 'http://localhost:8080/api/modePaiements' from origin 'http://localhost:4200' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request.
Also habe ich versucht, die keycloak.cors=trueEigenschaft hinzuzufügen application.properties. Wenn diese Eigenschaft hinzugefügt wird, GETfunktionieren die Aufrufe. Aber jetzt, wenn ich eine POST/PUTAPI aufrufe, erhalte ich eine Failed to load resource: the server responded with a status of 403 ()Fehlermeldung.
KeycloakWebSecurityConfigurerAdapter:
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.authorizeRequests().antMatchers("/api/*").hasRole("app-manager").anyRequest().permitAll();
}
Spring Sample Application: https://github.com/bilaldekar/kc
Winkelprobenanwendung: https://github.com/bilaldekar/kc-ang
Header anfordern:
Antworten
Sieht für mich nach einem CSRF-Problem aus.
Fügen Sie der Sicherheitskonfiguration Folgendes hinzu
http.authorizeRequests().antMatchers("/api/*").hasRole("app-manager").anyRequest().permitAll()
.and().csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
Der obige Code setzt das CSRF-Token in dem genannten Cookie XSRF-TOKEN. Angular liest dieses Cookie für CSRF-Token standardmäßig und fügt es in den nachfolgenden Anforderungen hinzu. Um sicherzustellen, dass Angular es lesen kann, setzen wir das Http onlyauf False. Dies hat seine eigenen Auswirkungen auf die Sicherheit, da auf das CSRF-Token jetzt per Skript zugegriffen werden kann. Wenn Sie dies nicht bevorzugen, besteht die andere Möglichkeit darin, das X-XSRF-TOKENToken aus dem Antwortheader zu lesen und es mit Angular Interceptor im nachfolgenden Anforderungsheader zu senden.
Aktualisieren:
Beim lokalen Testen, wo Angular auf 4200 ausgeführt wird, wird die Spring Boot-App und der Keycloak-Server auf 8080- und 8085-Ports ausgeführt.
Verwenden Sie den Webpack Dev Server-Proxy mit den folgenden Schritten. (Sie brauchen diese Konfiguration nicht mehr keycloak.cors=true)
im environment.tsUpdate derapiUrl
apiUrl: '', //Spring Boot API
Fügen Sie dann proxy.conf.jsonunter dem srcOrdner ein mit dem folgenden Inhalt hinzu
{
"/api": {
"target": "http://localhost:8080",
"secure": false
},
"logLevel": "debug"
}
Fügen Sie die Proxy-Konfiguration im angular.jsonBefehl serve hinzu
"options": {
"browserTarget": "kc-ang:build",
"proxyConfig": "src/proxy.conf.json"
}
Jetzt würden Sie feststellen, dass die API-Anforderungen an localhost: 4200 / api / * gehen und über die obige Konfiguration an die Spring-Boot-App weitergeleitet werden.
Damit wären die XSRF-bezogenen Cookies und der Header Teil der Anfrage und Sie sollten keine Probleme bekommen.
[! [Beispielarbeitsversion] [1]] [1]
Update 2: CORS unterstützen
Wenn sich Ihr Frontend und Backend in verschiedenen Domänen befinden und Sie CORS unterstützen müssen, müssen Sie dies tun
Die Sicherheitskonfiguration in Spring sollte CORS für den Ursprung des Frontends zulassen (in diesem Fall http: // localhost: 4200):
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.authorizeRequests().antMatchers("/api/*").hasRole("app-manager").anyRequest()
.permitAll()
.and().csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.and().cors();
}
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("http://localhost:4200"));
configuration.setAllowedMethods(Arrays.asList("GET","POST"));
configuration.setAllowCredentials(Boolean.TRUE);
configuration.addAllowedHeader("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/api/*", configuration);
return source;
}
Aktualisieren Sie in Angular die environment.tsDatei apiUrl in auf
apiUrl: '//localhost:8085'
Setzen Sie die withCredentialsOption auf, während Sie Schreibvorgänge (POST / PUT / DELETE) mit dem Angular http-Client ausführen true. (Stellen Sie außerdem sicher, dass die Methode für CORS in der serverseitigen Konfiguration unterstützt wird. In der obigen CORS-Konfiguration haben wir nur GET und POST zugelassen. Wenn Sie PUT / DELETE unterstützen müssen, stellen Sie sicher, dass Sie die CORS-Konfiguration entsprechend aktualisieren.)
In diesem Fall aktualisieren Sie die folgende Methode in fournisseur.service.ts
addFournisseur(fournisseur: Fournisseur): Observable<Fournisseur> {
return this.httpClient.post<Fournisseur>(this.envUrl + '/api/fournisseurs', fournisseur, {withCredentials: true});
}