使用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的访问令牌分两类:
- 不透明令牌:用于访问Google自身API,格式不是JWT,需要通过Google的令牌 introspection 接口验证
- JWT格式idToken:OpenID Connect流程返回的身份令牌,符合标准JWT格式,能被Spring的JWT资源服务器直接验证
你当前的配置只启用了JWT验证,而Postman生成的是第一种不透明令牌,所以触发401。
解决方案
方案1:同时支持JWT和Opaque Token验证
修改配置让资源服务器兼容两种令牌:
- 打开配置文件中
opaque-token的注释,填入正确的Google客户端ID和密钥 - 更新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(); }
- 完整的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格式的访问令牌:
- 请求令牌时必须包含
openidscope - 在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
相关产品推荐
相关产品推荐

