英文:
Okta blocks call from angular front end at localhost:4200 to spring boot backend at localhost:8080
问题
当使用Okta来保护API访问时,从本地主机的Angular应用(localhost:4200)到Spring Boot应用(localhost:8080)的跨域调用将被阻止,即使在控制器上放置了@CrossOrigin("*")。
以下是开发者控制台中的错误信息:
- XMLHttpRequest访问http://localhost:8080/api/messages从来源'http://localhost:4200'的请求已被CORS策略阻止:对预检请求的响应未通过访问控制检查:在所请求的资源上不存在'Access-Control-Allow-Origin'头部。*
以下是Angular应用的代码,该代码在标头中使用访问令牌向后端发出GET请求。
getMessages(): Observable<Message[]> {
const apiUrl = 'http://localhost:8080/api/messages';
const accessToken = this.oktaAuth.getAccessToken();
const headers = new HttpHeaders({'Authorization': 'Bearer ' + accessToken, 'Access-Control-Allow-Origin': 'http://localhost:4200'});
return this.http.get<Message[]>(apiUrl, {headers: headers});
}
前端和后端都与Okta身份验证集成。
如果从POM中移除Spring Boot Okta Starter依赖项,可以在控制器上放置@CrossOrigin("")来进行跨域调用。但如果在POM中包含Spring Boot Okta Starter,@CrossOrigin("")将不起作用。看起来Okta正在响应来自浏览器的预检请求。
尝试按照https://developer.okta.com/docs/guides/enable-cors/main/ 中的步骤启用CORS,并在受信任的来源(类型CORS)中列出了http://localhost:4200。但这并不起作用。Okta表示受信任的来源配置不适用于OAuth2。这似乎是一个常见情况。但我在互联网上找不到可行的解决方案。有人对此有解决方案吗?谢谢。
尝试按照https://developer.okta.com/docs/guides/enable-cors/main/ 启用CORS。
英文:
When Okta is used to secure API access, cross domain call from angular app at localhost:4200 to spring boot app at localhost:8080 will be blocked even with @CrossOrigin("*") placed on controller.
Below is the error in developer console:
Access to XMLHttpRequest at http://localhost:8080/api/messages from origin 'http://localhost:4200' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Here is the code of the angular app which makes a GET request to backend with an access token in headers.
getMessages(): Observable<Message[]>{
const apiUrl = 'http://localhost:8080/api/messages';
const accessToken = this.oktaAuth.getAccessToken();
const headers = new HttpHeaders({'Authorization': 'Bearer ' + accessToken, 'Access-Control-Allow-Origin': 'http://localhost:4200'});
return this.http.get<Message[]>(apiUrl, {headers: headers});
}
Both front end and backend are integrated with Okta authentication.
If spring boot Okta starter dependency is removed from POM, cross domain call can be made with @CrossOrigin("") placed at the controller. But if spring boot Okta starter is included in POM, @CrossOrigin("") will not work. Looks like OKta is responding to the preflight request from browser.
Tried to enable CORS by following https://developer.okta.com/docs/guides/enable-cors/main/
and have http://localhost:4200 listed in Trusted Origins ( type CORS ). But this does not work. Okta said Trusted Origins config does not work for OAuth2. This seems to be a common scenario. But I could not find a working solution on Internet. Anyone has a solution for this? Thanks
Tried to enable CORS by following https://developer.okta.com/docs/guides/enable-cors/main/
答案1
得分: 0
配置Angular应用程序作为(公共)OAuth2客户端不再被视为最佳实践。这适用于所有基于JavaScript的框架。如果您使用浏览器调试工具查看Gmail、Facebook、LinkedIn、GitHub等网站,您将无法找到带有Bearer
令牌的Authorization
标头的单个请求(您只会找到会话cookie)。
这是因为BFF模式:(机密的)OAuth2客户端是服务器上的中间件,负责隐藏浏览器和JavaScript代码中的令牌。浏览器和此中间件之间的请求受会话保护(以及防跨站请求伪造)。BFF在将请求转发到下游资源服务器之前,将会话cookie替换为OAuth2令牌。
现在谈到跨源资源共享(CORS):如果此中间件用于代理您的Angular应用程序和REST API,那么从浏览器的角度来看,所有请求都将具有相同的来源,神奇般地,您的CORS错误将不复存在。
spring-cloud-gateway
可以作为BFF使用,如果您将其配置为OAuth2客户端,并在路由到您的Spring资源服务器时添加TokenRelay=
过滤器。我写了一个完整的教程,在这里。
英文:
Configuring an Angular app as a (public) OAuth2 client is not considered a best practice anymore. This applies to all Javascript based frameworks. If you have a look at Gmail, Facebook, Linkedin, Github, etc., with your browser debugging tools, you won't find a single request with a Bearer
token in an Authorization
header (you'll just find session cookies).
The reason for this is the BFF pattern: the (confidential) OAuth2 client is a middleware on the server in charge of hiding tokens from the browser and Javascript code. Requests between the browser and this middleware are secured with sessions (and protection against CSRF). The BFF replaces the session cookie with the OAuth2 token in session before forwarding a request to downstream resource-server.
Now your CORS point: if this middleware is used to proxy both your Angular app and your REST API, then, from the browser point of view, all requests will have the same origin, and abracadabra, your CORS error will be gone.
spring-cloud-gateway
can be used as BFF if you configure it as an OAuth2 client and add the TokenRelay=
filter when routing to your Spring resource server(s). I wrote a complete tutorial there.
答案2
得分: 0
在我的经验中,当您将@CrossOrigin
与Spring Security集成时,它停止起作用。添加一个过滤器效果会更好。您可以尝试注册一个CORS过滤器,看看是否有效?
@Bean
public FilterRegistrationBean simpleCorsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.setAllowedOrigins(Collections.singletonList("http://localhost:4200"));
config.setAllowedMethods(Collections.singletonList("*"));
config.setAllowedHeaders(Collections.singletonList("*"));
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean bean = new FilterRegistrationBean<>(new CorsFilter(source));
bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return bean;
}
英文:
In my experience, @CrossOrigin
stops working when you integrate it with Spring Security. Adding a filter works much better. Can you try registering a CORS filter and see if that works?
@Bean
public FilterRegistrationBean simpleCorsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.setAllowedOrigins(Collections.singletonList("http://localhost:4200"));
config.setAllowedMethods(Collections.singletonList("*"));
config.setAllowedHeaders(Collections.singletonList("*"));
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean bean = new FilterRegistrationBean<>(new CorsFilter(source));
bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return bean;
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论