带有 Keycloak 的 Angular/Spring Boot 抛出 403
Posted
技术标签:
【中文标题】带有 Keycloak 的 Angular/Spring Boot 抛出 403【英文标题】:Angular/Spring Boot with Keycloak throws 403 【发布时间】:2021-01-09 12:18:12 【问题描述】:我在 this documentation 之后使用 Keycloak 11.0.2 和 Spring Security 保护了我的 Spring Boot 应用程序。
我在application.properties
中使用了基本的Keycloak配置:
keycloak.auth-server-url=http://localhost:8085/auth
keycloak.realm=cirta
keycloak.resource=cirta-api
keycloak.public-client=false
我有一个单独的前端 Angular 应用程序,它在 Keylocak 中配置为不同的客户端;但与 Spring Boot 应用程序处于同一领域。从 Angular 应用程序中,我在 HTTP 标头中发送 Keycloak 提供的令牌:
'Authorization' : 'Bearer ' + this.securityService.kc.token
当我访问调用 GET
API 的 Angular 页面时,我收到 blocked by CORS policy
错误:
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.
所以我尝试将keycloak.cors=true
属性添加到application.properties
。添加该属性后,GET
调用正在运行。但是现在当我调用 POST/PUT
API 时,我收到了 Failed to load resource: the server responded with a status of 403 ()
错误。
KeycloakWebSecurityConfigurerAdapter:
@Override
protected void configure(HttpSecurity http) throws Exception
super.configure(http);
http.authorizeRequests().antMatchers("/api/*").hasRole("app-manager").anyRequest().permitAll();
Spring 示例应用程序: https://github.com/bilaldekar/kc
Angular 示例应用程序: https://github.com/bilaldekar/kc-ang
请求标头:
【问题讨论】:
评论不用于扩展讨论;这个对话是moved to chat。this.securityService.kc.token
解码后的有效载荷是什么样的?有app-manager
角色吗?
我在问题中添加了令牌,是的,我创建了一个角色 app-manager。
@deduper 你能给出解决 401/403 的配置吗,我会用前端调用测试它,看看它是否有效
我发现后端 api 应该仅配置为承载,而不是公共客户端,以便通过前端发送的令牌提供对 api 的访问,但这并没有解决问题
【参考方案1】:
在我看来是一个 csrf 问题。
将以下内容添加到安全配置中
http.authorizeRequests().antMatchers("/api/*").hasRole("app-manager").anyRequest().permitAll()
.and().csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
以上代码将在名为XSRF-TOKEN
的cookie中设置CSRF令牌。默认情况下,Angular 会为 CSRF 令牌读取此 cookie,并将其添加到后续请求中。为了确保 Angular 可以读取它,我们将 Http only
设置为 False
。这有其自身的安全隐患,因为现在可以通过脚本访问 CSRF 令牌。如果您不喜欢这样做,另一种方法是从响应标头中读取X-XSRF-TOKEN
令牌,并使用 Angular 拦截器将其发送到后续请求标头中。
更新:
在本地测试时,Angular 运行在 4200、Spring Boot 应用、Keycloak 服务器在 8080、8085 端口上。
通过以下步骤使用 Webpack 开发服务器代理。 (你不再需要这个配置了keycloak.cors=true
)
在environment.ts
中更新apiUrl
apiUrl: '', //Spring Boot API
然后在src
文件夹下添加proxy.conf.json
,内容如下
"/api":
"target": "http://localhost:8080",
"secure": false
,
"logLevel": "debug"
在angular.json
serve 命令中添加代理配置
"options":
"browserTarget": "kc-ang:build",
"proxyConfig": "src/proxy.conf.json"
现在您会注意到 api 请求将转到 localhost:4200/api/* 并通过上述配置路由到 Spring Boot 应用程序。
这样,与 XSRF 相关的 cookie 和标头将成为请求的一部分,您应该不会遇到任何问题。
[![示例工作版本][1]][1]
更新 2:支持 CORS
如果你的前端和后端在不同的域上,如果你必须支持 CORS,那么这就是需要做的事情
Spring 上的安全配置应该允许 CORS 作为前端的来源(在本例中为 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;
在 Angular 上,将 environment.ts
文件中的 apiUrl 更新为
apiUrl: '//localhost:8085'
在使用 Angular http 客户端进行任何写入操作(POST/PUT/DELETE)时,请将withCredentials
选项设置为true
。 (还要确保服务器端配置上的 CORS 支持该方法。在上述 CORS 配置中,我们只允许 GET 和 POST。如果您需要支持 PUT/DELETE,请确保相应地更新 CORS 配置)
在这种情况下更新fournisseur.service.ts
中的以下方法
addFournisseur(fournisseur: Fournisseur): Observable<Fournisseur>
return this.httpClient.post<Fournisseur>(this.envUrl + '/api/fournisseurs', fournisseur, withCredentials: true);
【讨论】:
你能完全禁用 CSRF 并检查一下。这至少应该可以帮助您消除一种可能性。 我如何禁用 csrf,角度或弹簧? 您需要在 Spring 上禁用。在配置方法中调用禁用方法。 http.csrf().disable(); 所以我应该keeo http.csrf().disable();在我的配置中,这样安全吗? 如果您的 api 将仅被服务器访问,即后端到后端模型,那么您可以。如果要通过前端访问它,在这种情况下,你不应该。您是否会使用此答案中提到的配置检查您是否在响应中获得了“XSRF-TOKEN”cookie。如果是,那么只需要检查 Angular 方面(我现在也要看看)。如果不是,那么我们还必须查看 CSRF 配置的 Spring 端。以上是关于带有 Keycloak 的 Angular/Spring Boot 抛出 403的主要内容,如果未能解决你的问题,请参考以下文章
登录后带有 Spring 'Invalid credentials' 的 Keycloak
带有 OpenIdConnect 外部身份提供者的 Keycloak