Eureka Client作为OAuth2资源服务器转发Token时user-info-uri被误识别
你碰到的问题核心在于:给OAuth2RestTemplate加上@LoadBalanced后,这个模板会被Ribbon的负载均衡逻辑接管——它会尝试把所有请求的URL主机部分当作Eureka服务ID去解析,包括资源服务器用来获取用户信息的https://api.github.com/user,这显然不是你的内部微服务ID,所以自然会抛出解析异常。
这里有个简单直接的解决方案:分开两个RestTemplate实例,一个负责内部微服务的负载均衡调用,另一个专门给资源服务器用来访问外部的用户信息端点:
步骤1:创建专门用于用户信息请求的RestTemplate
创建一个不带@LoadBalanced注解的RestTemplate Bean,避免被Ribbon的负载均衡拦截器影响:
@Bean public RestTemplate userInfoRestTemplate() { return new RestTemplate(); }
步骤2:配置资源服务器使用这个特定的RestTemplate
在你的YAML配置里,明确指定资源服务器要使用上面创建的这个RestTemplate:
security: oauth2: resource: user-info-uri: https://api.github.com/user rest-template: userInfoRestTemplate # 对应上面定义的Bean名称
步骤3:保留负载均衡的OAuth2RestTemplate用于内部调用
你原来标注@LoadBalanced的OAuth2RestTemplate可以保留,专门用来调用你的内部微服务(比如hbase-customer-reader):
@LoadBalanced @Bean public OAuth2RestTemplate oAuth2RestTemplate(UserInfoRestTemplateFactory factory) { return factory.getUserInfoRestTemplate(); }
这样配置后,资源服务器获取用户信息的请求会用我们单独配置的userInfoRestTemplate,不会触发负载均衡解析逻辑;而调用内部微服务的请求则用带@LoadBalanced的模板,正常通过Eureka服务ID路由到对应的实例。
顺便补充下原理:@LoadBalanced本质是给RestTemplate添加了LoadBalancerInterceptor拦截器,这个拦截器会把URL中的主机名替换为Eureka中注册的服务实例地址。当这个拦截器作用到资源服务器的用户信息请求时,就会把api.github.com当成服务ID去Eureka里查找,自然找不到就报错了,分开实例就能彻底避免这个冲突。
内容的提问来源于stack exchange,提问作者FabN

