You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular Keycloak适配器生成的Token无法通过Spring Boot后端授权验证

问题:Angular Keycloak适配器生成的Token无法访问Spring Boot后端

Keycloak基础配置

  • 版本:Keycloak 22.0.3,本地默认端口启动
  • Angular与Spring Boot使用同一Realm下的不同客户端

Angular客户端配置

  • 客户端ID:angular-client
  • URIs配置:适配Angular应用地址
  • 流程配置:标准授权流程
  • 其余为默认配置

Spring Boot客户端配置

  • 客户端ID:spring-client
  • URIs配置:适配Spring Boot应用地址
  • 流程配置:与Angular一致的标准授权流程
  • 其余为默认配置

Angular适配器实现

使用keycloak-angular 14.1.0库,初始化配置如下:

Provider代码:

{
  provide: APP_INITIALIZER,
  useFactory: initializeKeycloak,
  multi: true,
  deps: [KeycloakService]
}

Factory代码:

function initializeKeycloak (keycloak: KeycloakService) {
  return () =>
    keycloak.init ({
      config: {
        url: 'example.com:8080',
        realm: 'SpringBootKeycloak',
        clientId: 'angular-client'
      },
      initOptions: {
        onLoad: 'check-sso',
        silentCheckSsoRedirectUri:
          window.location.origin + '/assets/silent-check-sso.html'
      }
    });
}

Angular端登录、登出及Web授权正常,但生成的Access Token无法通过Spring Boot后端验证

Spring Boot安全配置

application.properties配置

spring.security.oauth2.client.registration.keycloak.client-id=spring-client
spring.security.oauth2.client.registration.keycloak.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.keycloak.scope=openid
spring.security.oauth2.client.provider.keycloak.issuer-uri=example.com:8080/realms/SpringBootKeycloak
spring.security.oauth2.client.provider.keycloak.user-name-attribute=preferred_username
spring.security.oauth2.resourceserver.jwt.issuer-uri=example.com:8080/realms/SpringBootKeycloak
spring.security.oauth2.resourceserver.jwt.jwk-set-uri=example.com:8880/auth/realms/SpringBootKeycloak/protocol/openid-connect/certs

SecurityConfig代码

@Configuration
@EnableWebSecurity
@EnableMethodSecurity
class SecurityConfig {

    SecurityConfig() {
    }

    @Bean
    protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
        return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
    }


    @Order(1)
    @Bean
    public SecurityFilterChain resourceServerFilterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests(auth -> auth.anyRequest().authenticated());
        http.oauth2ResourceServer((oauth2) -> oauth2
                .jwt(Customizer.withDefaults()));
        return http.build();
    }

    @Bean
    public AuthenticationManager authenticationManager(HttpSecurity http) throws Exception {
        return http.getSharedObject(AuthenticationManagerBuilder.class)
                .build();
    }

}

有效Token测试示例

通过密码模式获取的Token可正常访问后端:

获取Token

POST example.com:8080/realms/SpringBootKeycloak/protocol/openid-connect/token
Content-Type: application/x-www-form-urlencoded

client_id=spring-client&username=user&password=password&grant_type=password

使用Token请求接口

GET example.com:8081/api/resource
Authorization: Bearer {{token}}

错误信息

浏览器返回

401 Unauthorized
x-frame-options DENY

Spring Boot控制台栈跟踪

java.lang.StackOverflowError: null
    at org.springframework.aop.support.AopUtils.isEqualsMethod(AopUtils.java:151) ~[spring-aop-6.0.9.jar:6.0.9]
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:175) ~[spring-aop-6.0.9.jar:6.0.9]
    at jdk.proxy2/jdk.proxy2.$Proxy175.authenticate(Unknown Source) ~[na:na]
    at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:201) ~[spring-security-core-6.1.0.jar:6.1.0]

已尝试无效方案

手动配置JwtDecoder指定RS256签名算法,未解决问题:

@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class WebSecurityConfig {
@Value("${spring.security.oauth2.resourceserver.jwt.jwk-set-uri}")
private String jwkSetUri;

@Bean
public JwtDecoder jwtDecoder() {
return NimbusJwtDecoder.withJwkSetUri(jwkSetUri).jwsAlgorithm(SignatureAlgorithm.RS256).build();
}
}

预期目标

使用Angular适配器生成的Access Token完成Spring Boot后端REST接口的授权验证


解决建议

  1. 检查Token受众与权限
    解析Angular生成的Token,确认aud字段包含spring-client,或在Keycloak客户端配置中开启"Full Scope Allowed",确保Token拥有访问后端的权限。

  2. 修正JWK-Set URI端口错误
    当前配置中jwk-set-uri端口为8880,与Keycloak默认端口8080不符,修改为:

    spring.security.oauth2.resourceserver.jwt.jwk-set-uri=example.com:8080/realms/SpringBootKeycloak/protocol/openid-connect/certs
    
  3. 移除冗余AuthenticationManager Bean
    资源服务器模式下无需手动定义AuthenticationManager,该Bean会引发循环调用导致栈溢出,删除以下代码:

    @Bean
    public AuthenticationManager authenticationManager(HttpSecurity http) throws Exception {
        return http.getSharedObject(AuthenticationManagerBuilder.class)
                .build();
    }
    
  4. 确保请求正确携带Token
    实现Angular HTTP拦截器,自动为请求添加Token头:

    @Injectable()
    export class AuthInterceptor implements HttpInterceptor {
      constructor(private keycloakService: KeycloakService) {}
    
      intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        return from(this.keycloakService.getToken()).pipe(
          switchMap(token => {
            if (token) {
              request = request.clone({
                setHeaders: {
                  Authorization: `Bearer ${token}`
                }
              });
            }
            return next.handle(request);
          })
        );
      }
    }
    
  5. 配置后端CORS允许跨域
    Spring Boot添加CORS配置Bean,允许Angular应用跨域请求:

    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        config.addAllowedOrigin("http://example.com:4200"); // 替换为Angular实际地址
        config.addAllowedHeader("*");
        config.addAllowedMethod("*");
        source.registerCorsConfiguration("/**", config);
        return new CorsFilter(source);
    }
    

内容的提问来源于stack exchange,提问作者Slawomir

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 04:33:20