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

使用Google JWT访问令牌作为Spring认证服务器时遇401未授权

问题:Spring资源服务器调用返回401,仅idToken可用,如何让JWT访问令牌正常工作?

背景信息

技术栈:Spring Boot 3、Google API、Postman
正在搭建Spring Boot服务访问Google Gmail和Calendar,将Google OAuth2作为授权服务器,Spring Boot作为资源服务器,已按官方指南配置安全规则。测试时发现:

  • 用Postman生成的访问令牌调用接口返回401 Unauthorized
  • 换成idToken则能正常访问
  • 尝试Opaque Token配置仍报错

现有安全配置

@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfiguration {

  @Bean
  public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
        .csrf(e -> e.disable())
        .httpBasic(e -> e.disable())
        .formLogin(e -> e.disable())
        .authorizeHttpRequests(authz -> authz
            .requestMatchers("/**")
            .fullyAuthenticated()
        )
        .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt)
        .sessionManagement(sess -> sess.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
    ;
    return http.build();
  }
}

现有Spring配置文件

spring:
  security:
    oauth2:
#      client:
#        registration:
#          google:
#            client-id: xxx
#            client-secret: xxx
#            scope:
#              - openid
#              - profile
#              - email
      resourceserver:
        jwt:
          issuer-uri: https://accounts.google.com
          jwk-set-uri: https://www.googleapis.com/oauth2/v3/certs
#        opaque-token:
#          introspection-uri: https://oauth2.googleapis.com/tokeninfo
#          client-id: xxx
#          client-secret: xxx

问题根源

Google OAuth2的访问令牌分两类:

  1. 不透明令牌:用于访问Google自身API,格式不是JWT,需要通过Google的令牌 introspection 接口验证
  2. JWT格式idToken:OpenID Connect流程返回的身份令牌,符合标准JWT格式,能被Spring的JWT资源服务器直接验证

你当前的配置只启用了JWT验证,而Postman生成的是第一种不透明令牌,所以触发401。

解决方案

方案1:同时支持JWT和Opaque Token验证

修改配置让资源服务器兼容两种令牌:

  1. 打开配置文件中opaque-token的注释,填入正确的Google客户端ID和密钥
  2. 更新SecurityFilterChain,同时启用JWT和Opaque Token验证:
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
        .csrf(CsrfConfigurer::disable)
        .httpBasic(HttpBasicConfigurer::disable)
        .formLogin(FormLoginConfigurer::disable)
        .authorizeHttpRequests(authz -> authz.anyRequest().fullyAuthenticated())
        .oauth2ResourceServer(oauth2 -> oauth2
            .jwt(Customizer.withDefaults())
            .opaqueToken(Customizer.withDefaults())
        )
        .sessionManagement(sess -> sess.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
    return http.build();
}
  1. 完整的Spring配置示例:
spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: https://accounts.google.com
          jwk-set-uri: https://www.googleapis.com/oauth2/v3/certs
        opaque-token:
          introspection-uri: https://oauth2.googleapis.com/tokeninfo
          client-id: 你的Google客户端ID
          client-secret: 你的Google客户端密钥

方案2:获取JWT格式的访问令牌

Google在满足以下条件时会返回JWT格式的访问令牌:

  • 请求令牌时必须包含openid scope
  • 在Google Cloud控制台把OAuth客户端配置为Web应用,并设置正确的授权回调地址
  • 使用Authorization Code Flow获取令牌(Client Credentials Flow返回的是不透明令牌)

方案3:自定义JWT解码器适配Google令牌

如果一定要用JWT方式验证Google的访问令牌,需要自定义JwtDecoder来适配其格式:

@Bean
public JwtDecoder jwtDecoder() {
    NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withJwkSetUri("https://www.googleapis.com/oauth2/v3/certs").build();
    // 自定义验证规则,比如检查受众是否包含你的客户端ID
    jwtDecoder.setJwtValidator(JwtValidators.createDefaultWithIssuer("https://accounts.google.com"));
    return jwtDecoder;
}

注意:需要确保请求令牌时,aud(受众)字段包含你的Spring应用客户端ID,否则需要修改验证逻辑跳过受众检查(不推荐,会降低安全性)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 03:23:22