Spring OAuth2资源服务器集成测试报Invalid token错误
OAuth2资源服务器集成测试替换令牌报invalid_token错误排查
问题背景
- 调试Spring官方简易OAuth2资源服务器示例,重点研究其集成测试实现,计划将测试逻辑复用到自有项目
- 尝试将集成测试内置的测试令牌,替换为Spring Authorization Server官方示例生成的访问令牌,替换后接口请求抛出如下错误:
WWW-Authenticate:"Bearer error="invalid_token", error_description="An error occurred while attempting to decode the Jwt: Signed JWT rejected: Another algorithm expected, or no matching key(s) found", error_uri="https://tools.ietf.org/html/rfc6750#section-3.1""
- 已将资源服务器示例中
MockWebServerPropertySource配置的JWKS的n参数,替换为授权服务器示例JWKS对应的n参数,修改后仍然抛出完全相同的错误 - 观察到授权服务器示例生成的访问令牌,和资源服务器示例中原生使用的测试令牌结构存在差异,需要定位集成测试场景下令牌无法通过校验的根因,给出正确修改
OAuth2ResourceServerApplicationITests测试文件中令牌配置的方案,实现替换自定义生成令牌后测试正常通过
两类令牌示例
1. Spring Authorization Server示例生成的令牌
eyJraWQiOiIwMjg2OWFlZC1hZjQwLTQ5MmEtYWFlYy1mMWZhMTI1N2UzZWUiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJtZXNzYWdpbmctY2xpZW50IiwiYXVkIjoibWVzc2FnaW5nLWNsaWVudCIsIm5iZiI6MTY1NzExNDQ3OCwic2NvcGUiOlsibWVzc2FnZTpyZWFkIl0sImlzcyI6Imh0dHA6XC9cL2xvY2FsaG9zdDo5MDAwIiwiZXhwIjoxNjU3MTE0Nzc4LCJpYXQiOjE2NTcxMTQ0Nzh9.IB57Lix9R6F7sL5Ai5hc0o8DbWfxzXCnCEp6HL8vYu3XyVYx-wPthb5vTX4vsoBrebFsgIBkO63At4R3mfpkJSZO72bA7o-OkJEW0-n3MQwTRDZssy7-wvCG_dnRJ2OPlInaXqOogzWRfETI-7l_Ey5pxjQoKUGzA0Omqm2OtdVzy5X7qUlsDJ3rYuI34092bTZJGP3O3RuXkuJaP6GSkhG4sForttj6aFMviXDPeNJ5zpuyWBMC5bRunvVhCo2NOkHoL8BMr1s8FLySrNCGbIEOE9lkZxDJ3LZ7pH3hsbFuhn7jXYlZ4J5sFEu6c0kHHVLU7ti4cm_7VYp7DRV91g
解码后JWT头:
{"kid":"02869aed-af40-492a-aaec-f1fa1257e3ee","alg":"RS256"}
2. 资源服务器示例原有测试令牌
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJzdWJqZWN0IiwiZXhwIjoyMTY0MjQ1NjQ4LCJhdXRob3JpdGllcyI6WyJST0xFX1VTRVIiXSwianRpIjoiY2I1ZGMwNDYtMDkyMi00ZGJmLWE5MzAtOGI2M2FhZTYzZjk2IiwiY2xpZW50X2lkIjoicmVhZGVyIiwic2NvcGUiOlsibWVzc2FnZTpyZWFkIl19.Pre2ksnMiOGYWQtuIgHB0i3uTnNzD0SMFM34iyQJHK5RLlSjge08s9qHdx6uv5cZ4gZm_cB1D6f4-fLx76bCblK6mVcabbR74w_eCdSBXNXuqG-HNrOYYmmx5iJtdwx5fXPmF8TyVzsq_LvRm_LN4lWNYquT4y36Tox6ZD3feYxXvHQ3XyZn9mVKnlzv-GCwkBohCR3yPow5uVmr04qh_al52VIwKMrvJBr44igr4fTZmzwRAZmQw5rZeyep0b4nsCjadNcndHtMtYKNVuG5zbDLsB7GGvilcI9TDDnUXtwthB_3iq32DAd9x8wJmJ5K8gmX6GjZFtYzKk_zEboXoQ
解码后JWT头:
{"alg":"RS256","typ":"JWT"}
问题根因
- 核心原因:kid不匹配导致公钥定位失败
JWT验签流程会优先读取JWT头中的kid(密钥ID)字段,到JWKS接口返回的公钥集合中匹配对应ID的公钥做验签。原测试令牌没有携带kid字段,测试配置的JWKS仅存在一个公钥,因此可以直接匹配成功;但替换后的授权服务器令牌携带了唯一kid值,仅替换JWKS的n参数时,Mock返回的JWKS中公钥的kid还是原有测试值,和令牌中的kid不一致,无法定位到正确公钥,直接抛出密钥不匹配错误。 - 潜在校验不通过点
示例中给出的授权服务器生成令牌exp字段对应时间为2022年7月6日,早已超出有效期,即便密钥匹配也会触发令牌过期错误;另外如果资源服务器配置了签发者(iss)、受众(aud)校验,授权服务器签发的令牌中iss值为http://localhost:9000,和测试Mock服务地址不匹配也会导致校验失败。
修复步骤
- 第一步:替换完整JWKS配置
不要仅修改n参数,需要将授权服务器签发令牌所用密钥对对应的完整JWKS(包含kid、kty、alg、n、e全部字段)替换到MockWebServerPropertySource的JWKS配置中,保证Mock返回的公钥kid和所用JWT头中的kid完全一致,公钥参数和签发令牌的私钥一一对应。 - 第二步:保证令牌本身有效性
不要直接使用历史生成的过期令牌,二选一即可:- 测试代码中直接使用授权服务器的RSA密钥对自行构建JWT,手动设置足够长的过期时间、与测试配置匹配的
iss、aud、scope等必要声明 - 若需使用授权服务器实时签发的令牌,测试时可启动授权服务器测试实例,或对齐Mock服务地址与令牌中
iss声明值,保证测试执行时令牌处于有效期内
- 测试代码中直接使用授权服务器的RSA密钥对自行构建JWT,手动设置足够长的过期时间、与测试配置匹配的
- 第三步:对齐测试环境配置
确保测试环境下资源服务器的spring.security.oauth2.resourceserver.jwt.issuer-uri配置指向MockWebServer地址,与所用令牌的iss声明值完全一致;若配置了受众校验,需同步保证令牌中aud声明与资源服务器预期值匹配。
内容的提问来源于stack exchange,提问作者bojackhorseman99
相关产品推荐
相关产品推荐

