Spring boot Oauth2:使用 Feign、Ribbon、Zull 和 Eureka 从客户端到资源的令牌中继

Posted

技术标签:

【中文标题】Spring boot Oauth2:使用 Feign、Ribbon、Zull 和 Eureka 从客户端到资源的令牌中继【英文标题】:Spring boot Oauth2 : Token relay from a client using Feign, Ribbon, Zull and Eureka to a ressource 【发布时间】:2019-04-24 04:16:43 【问题描述】:

我有一个成功从授权服务器获取令牌的 oauth2 客户端。 (并非总是如此,但现在是...... :))

客户端、zuul网关和资源服务器都注册在Eureka中。

我的客户端使用代理访问名为 m​​icroservice-files 的远程资源服务。

@RestController
@FeignClient(name = "zuul-server")
@RibbonClient(name = "microservice-files")

public interface ProxyMicroserviceFiles 

    @GetMapping(value = "microservice-files/root")
    FileBean getUserRoot();


所以我想将令牌转发给 Zull,然后转发给资源服务器。

我可以通过这种方式传递令牌以联系 Zuul,显然负载平衡也得到了管理(我刚刚测试了我不知道,这很棒)zuul 也可以传递令牌,但这不是很方便我d更喜欢以前的方法。

@EnableConfigurationProperties
@SpringBootApplication
@EnableFeignClients("com.clientui")
public class ClientUiApplication 

    @Bean
    public OAuth2RestOperations restOperations(
            OAuth2ProtectedResourceDetails resource, 
            OAuth2ClientContext context) 

        return new OAuth2RestTemplate(resource, context);
    

    public static void main(String[] args) 

        SpringApplication.run(ClientUiApplication.class, args);
    

这里是测试控制器

@Controller
public class ClientController 

    @Autowired
    private RestOperations restOperations;

    @RequestMapping("/root")
    public ResponseEntity userRootTest() 

       String rootUrl = "http://localhost:9004/microservice-files/root";

       return  restOperations.getForEntity(rootUrl,FileBean.class);

    


【问题讨论】:

在这里找到解决方案***.com/questions/29439653/… 答案有点旧(3 年前),但它仍然可以完美运行。我不知道是否存在更新的更好的解决方案。 【参考方案1】:

如果我正确理解了您的问题,那么您可以使用 RequestInterceptor 在假装的每个请求中添加一个令牌。为了做到这一点,你可以使用下一个配置:

@Bean
public RequestInterceptor oauth2FeignRequestInterceptor(OAuth2ClientContext oauth2ClientContext,
                                                        OAuth2ProtectedResourceDetails resource) 
    return new OAuth2FeignRequestInterceptor(oauth2ClientContext, resource);


@Bean
protected OAuth2ProtectedResourceDetails resource() 
    AuthorizationCodeResourceDetails resource = new AuthorizationCodeResourceDetails();
    resource.setAccessTokenUri("http://127.0.0.1:9000/auth/login");
    resource.setUserAuthorizationUri("http://127.0.0.1:9000/auth/authorize");
    resource.setClientId("my-client");
    resource.setClientSecret("my-secret");
    return resource;

【讨论】:

感谢您的回答,它完美运行。我不知道哪一个是最好的解决方案。另一个只是在标头中添加令牌,它被中继,最后资源服务器可以检查它。在这里,我猜我们在客户端的每个 feign 请求中都会联系授权服务器。 OAuth2FeignRequestInterceptor 不会尝试在每个 feign 请求上获取新的令牌,这是实现仅当它在 OAuth2ClientContext 中丢失时才获取令牌,然后将此令牌放入上下文中并仅在令牌过期时刷新令牌。在这种情况下,您无需担心性能。 好的,如果其他解决方案没有在必要时刷新令牌;这是最好的解决方案 :) 感谢您的贡献 有没有办法,我们可以使用 Eureka 发现的名称而不是硬编码: resource.setAccessTokenUri("127.0.0.1:9000/auth/login"); //硬编码 resource.setAccessTokenUri("oauth-server/auth/login"); // 发现尤里卡。 .如果我尝试 Eureka Discovered name(oauth-server),我会收到错误:UnknownHostException @Hamid 我认为这是另一个问题,不幸的是解决起来并不简单。我希望这会有所帮助:github.com/spring-cloud/spring-cloud-security/issues/61【参考方案2】:

这就是我所做的。

 @Bean(name = "oauth2RestTemplate")
    @LoadBalanced
    public OAuth2RestTemplate restTemplate(SpringClientFactory clientFactory) 
        OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(resourceDetails());
        RibbonLoadBalancerClient ribbonLoadBalancerClient = new RibbonLoadBalancerClient(clientFactory);
        LoadBalancerInterceptor loadBalancerInterceptor = new LoadBalancerInterceptor(ribbonLoadBalancerClient);
        ClientCredentialsAccessTokenProvider accessTokenProvider = new ClientCredentialsAccessTokenProvider();
        accessTokenProvider.setInterceptors(Arrays.asList(loadBalancerInterceptor));
        restTemplate.setAccessTokenProvider(accessTokenProvider);

        return restTemplate;
    

    public ClientCredentialsResourceDetails resourceDetails() 
        ClientCredentialsResourceDetails clientCredentialsResourceDetails = new ClientCredentialsResourceDetails();
        clientCredentialsResourceDetails.setId("1");
        clientCredentialsResourceDetails.setClientId("my-ms");
        clientCredentialsResourceDetails.setClientSecret("123");
        clientCredentialsResourceDetails.setAccessTokenUri("http://oauth-server/oauth/token");
        clientCredentialsResourceDetails.setScope(Arrays.asList("read"));
        clientCredentialsResourceDetails.setGrantType("client_credentials");
        
        return clientCredentialsResourceDetails;
    

【讨论】:

以上是关于Spring boot Oauth2:使用 Feign、Ribbon、Zull 和 Eureka 从客户端到资源的令牌中继的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot 和 OAuth2 社交登录,无法获取 refreshToken

如何使用spring-boot 1.3.0.RC1为oauth2提供自定义安全性配置

让 oauth2 与 spring-boot 和 rest 一起工作

在反向代理后面使用 OAuth2 的 Spring Boot

带有 Spring Boot REST 应用程序的 OAuth2 - 无法使用令牌访问资源

如何在 Spring Boot 中使用 IPwhitelisting 和 OAuth2? [复制]