Spring Resource Server集成Spring Security OAuth2(Google)认证失败:JWT无效问题求助
解决Google Access Token在Spring Security OAuth2资源服务器中验证失败的问题
首先,你踩的坑我之前也遇到过——Google返回的access_token并不是标准JWT格式,但你当前的Spring Security配置是按照JWT资源服务器来搭建的,JwtAuthenticationProvider自然会把它当成JWT去解析,结果肯定报错。
下面给你两种落地可行的解决方案,按需选择:
方案一:适配现有Access Token(无需前端改动)
这种方案不用麻烦前端调整,后端通过调用Google官方的token验证接口来校验合法性:
- 确保依赖齐全:项目中需要引入Spring Security OAuth2资源服务器和WebClient依赖(用来调用Google的验证接口)
- 自定义Token验证逻辑:
- 写一个自定义的
AuthenticationProvider,调用Google的tokeninfo接口校验access_token - 替换Spring Security默认的JWT验证逻辑,改用这个自定义Provider
- 写一个自定义的
示例Kotlin代码:
@Component class GoogleAccessTokenAuthProvider(private val webClient: WebClient) : AuthenticationProvider { override fun authenticate(authentication: Authentication): Authentication { val bearerToken = authentication.credentials.toString() // 调用Google的token验证接口 val tokenInfo = webClient.get() .uri("https://www.googleapis.com/oauth2/v3/tokeninfo?access_token={token}", bearerToken) .retrieve() .bodyToMono(GoogleTokenInfo::class.java) .block() ?: throw BadCredentialsException("无效的Token") // 可选但推荐:验证Token的受众是否匹配你的客户端ID if (tokenInfo.aud != "<你的Google客户端ID>") { throw BadCredentialsException("Token受众不匹配") } // 构建认证成功的身份信息 val authorities = listOf(SimpleGrantedAuthority("ROLE_USER")) return UsernamePasswordAuthenticationToken(tokenInfo.email, null, authorities) } override fun supports(authentication: Class<*>): Boolean { return BearerTokenAuthenticationToken::class.java.isAssignableFrom(authentication) } } // 接收Google返回的Token信息的数据类 data class GoogleTokenInfo( val aud: String, val email: String, val exp: Long, val sub: String )
然后修改Spring Security配置,注册这个自定义Provider:
@Configuration @EnableWebSecurity(debug = true) @EnableGlobalMethodSecurity(prePostEnabled = true) class SpringSecurityConfig( private val googleAccessTokenAuthProvider: GoogleAccessTokenAuthProvider ) { @Bean fun filterChain(http: HttpSecurity): SecurityFilterChain { http .authorizeRequests() .antMatchers("/**").fullyAuthenticated() .and() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .oauth2ResourceServer() .bearerTokenResolver(BearerTokenResolver { it.getHeader("Authorization")?.removePrefix("Bearer ") }) .authenticationManager(ProviderManager(listOf(googleAccessTokenAuthProvider))) .and() .cors().and().csrf().disable() return http.build() } @Bean fun webClient(): WebClient { return WebClient.create() } }
方案二:改用Google的ID Token(更简洁)
如果能协调前端修改,让前端在Google登录时获取id_token(这是标准JWT格式),那你当前的大部分配置都能复用:
- 前端请求Google授权时,确保
scope包含openid(你已经配置了),并且获取id_token而非access_token - 后端的Spring Security配置不用大改——你当前的
issuer-uri和jwk-set-uri配置是正确的,直接用就行
当前端把id_token放在Authorization头里发送请求时,Spring Security的JWT验证逻辑就能正常工作了。
问题根源补充
Google OAuth2返回的access_token是不透明令牌,只用来访问Google的API,本身不是JWT;而id_token是符合OpenID Connect标准的JWT,包含用户身份信息,且可以通过公钥验证签名,这才是Spring Security OAuth2资源服务器默认支持的令牌类型。
内容的提问来源于stack exchange,提问作者Yan Frankovski
相关产品推荐
相关产品推荐

