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

Spring Authorization Server+Angular SPA调用/oauth2/token返回403禁止访问

Spring Authorization Server + PKCE 403 Forbidden 问题排查

核心问题定位

日志明确显示客户端认证通过但请求授权被拒,说明问题出在令牌请求的权限校验环节,而非客户端身份验证。重点排查PKCE参数合法性、客户端配置、令牌端点权限规则这几个方向。

排查步骤及解决方案

1. 校验PKCE参数完整性与正确性

PKCE流程要求令牌请求必须携带code_verifier,且需和授权请求中的code_challenge/code_challenge_method严格匹配:

  • 确认Angular请求(及Postman测试)中是否包含code_verifier参数,值必须是授权请求时生成的原始随机字符串(未经过哈希编码)
  • 若授权请求用了S256哈希算法,令牌请求无需传code_challenge_method,但code_verifier必须能通过S256哈希生成之前的code_challenge
  • Postman测试需手动模拟完整PKCE流程:先调用授权端点获取code,再用对应的code_verifier调用令牌端点,禁止重复使用同一code(授权码仅能使用一次)

2. 检查客户端注册配置

确保客户端配置符合SPA+PKCE的要求:

  • 客户端类型必须设为PUBLIC,即配置clientSettings.setClientAuthenticationMethod(ClientAuthenticationMethod.NONE),因为SPA无法安全存储客户端密钥
  • 必须启用PKCE:通过clientSettings.setAuthorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)并添加OAuth2AuthorizationCodeGrantConfigurer::requireProofKey
  • redirect_uri必须和Angular应用的回调地址完全匹配(包括协议、端口、路径,大小写敏感)
  • 令牌请求的scope必须和授权请求一致,且是客户端已配置的权限范围

正确的客户端注册代码示例:

@Bean
public RegisteredClientRepository registeredClientRepository() {
    RegisteredClient angularClient = RegisteredClient.withId(UUID.randomUUID().toString())
            .clientId("angular-spa")
            .clientAuthenticationMethod(ClientAuthenticationMethod.NONE)
            .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
            .redirectUri("http://localhost:4200/callback")
            .scope(OidcScopes.OPENID)
            .scope(OidcScopes.PROFILE)
            .clientSettings(ClientSettings.builder()
                    .requireAuthorizationConsent(false)
                    .requireProofKey(true) // 强制启用PKCE
                    .build())
            .build();
    return new InMemoryRegisteredClientRepository(angularClient);
}

3. 确认安全配置的端点权限

确保令牌端点/oauth2/token允许匿名访问(PUBLIC客户端无需客户端认证):

  • 若自定义了authorizeHttpRequests规则,需显式对/oauth2/token设置permitAll,避免覆盖默认规则。示例配置:
@Bean
public SecurityFilterChain authServerSecurityFilterChain(HttpSecurity http) throws Exception {
    OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
    http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
            .oidc(Customizer.withDefaults()); // 启用OIDC功能
    http
            .exceptionHandling(exceptions -> exceptions
                    .authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login")))
            .oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()));
    // 显式允许令牌端点匿名访问
    http.authorizeHttpRequests(auth -> auth
            .requestMatchers("/oauth2/token").permitAll()
            .anyRequest().authenticated());
    return http.build();
}

4. 校验oidc-client-ts配置

确保Angular端的OIDC客户端配置正确:

  • response_type必须设为code(授权码模式)
  • requirePkce设为true
  • client_id、redirect_uri、scope需和认证服务器的客户端配置完全一致

示例配置:

import { UserManager, UserManagerSettings } from 'oidc-client-ts';

const settings: UserManagerSettings = {
  authority: 'http://localhost:8080',
  client_id: 'angular-spa',
  redirect_uri: 'http://localhost:4200/callback',
  response_type: 'code',
  scope: 'openid profile',
  requirePkce: true,
  loadUserInfo: true
};

export const userManager = new UserManager(settings);

5. 深挖日志细节

从认证服务器日志中定位具体拒绝原因:

  • 查找是否有invalid_code_verifier、code_mismatch等关键字,这类信息直接指向PKCE参数错误
  • 确认授权码code未被重复使用,重复使用会直接触发403
  • 检查请求的grant_type是否为authorization_code,参数格式是否符合OAuth2规范

常见坑点

  • code_verifier长度必须在43-128字符之间,否则会被拒绝
  • 授权请求和令牌请求的客户端IP、用户代理等上下文不一致,可能被Spring Security的CSRF或会话保护拦截(SPA场景建议关闭令牌端点的CSRF校验)
  • 认证服务器启用HTTPS但Angular应用用HTTP,会导致redirect_uri不被允许(开发环境建议统一用HTTP,生产环境统一用HTTPS)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 20:22:43