首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Spring @FeignClient与OAuth2FeignRequestInterceptor不工作

Spring @FeignClient与OAuth2FeignRequestInterceptor不工作
EN

Stack Overflow用户
提问于 2016-01-08 12:45:08
回答 3查看 14.1K关注 0票数 5

我正在尝试将FeignClient与OAuth2一起设置为实现“中继令牌”。我只想让FeignClient中继/传播来自ZuulProxy (SSO已启用)的OAuth2令牌。我使用Spring1.3.1-发布SpringCloudBrixton.M4

我在自定义@FeignClient配置中添加了一个拦截器:

代码语言:javascript
复制
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.security.oauth2.client.feign.OAuth2FeignRequestInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.client.OAuth2ClientContext;
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails;

import feign.RequestInterceptor;

@Configuration
public class FeignClientConfiguration {

@Value("${security.oauth2.client.userAuthorizationUri}")
private String authorizeUrl;

@Value("${security.oauth2.client.accessTokenUri}")
private String tokenUrl;

@Value("${security.oauth2.client.client-id}")
private String clientId;


// See https://github.com/spring-cloud/spring-cloud-netflix/issues/675
@Bean
public RequestInterceptor oauth2FeignRequestInterceptor(OAuth2ClientContext oauth2ClientContext){
    return new OAuth2FeignRequestInterceptor(oauth2ClientContext, resource());
}

@Bean
protected OAuth2ProtectedResourceDetails resource() {
    AuthorizationCodeResourceDetails resource = new AuthorizationCodeResourceDetails();
    resource.setAccessTokenUri(tokenUrl);
    resource.setUserAuthorizationUri(authorizeUrl);
    resource.setClientId(clientId);
    // TODO: Remove this harcode 
    resource.setClientSecret("secret");
    return resource;
}   
}

我将配置添加到我的@FeignClient中,如下所示:

代码语言:javascript
复制
@FeignClient(name = "car-service", configuration =     FeignClientConfiguration.class)
interface CarClient {               
    @RequestMapping(value = "car-service/api/car", method = GET)
    List<CarVO> getAllCars();
}   

应用程序将启动,但当我使用服务中的冒牌客户端时,我得到:

代码语言:javascript
复制
2016-01-08 13:14:29.757 ERROR 3308 --- [nio-9081-exec-1] o.a.c.c.C.[.[.[.    [dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in 

    context with path [/user-service] threw exception [Request processing failed; nested exception is com.netflix.hystrix.exception.HystrixRuntimeException: getAllCars failed and no fallback available.] with root cause

    java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
at org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131) ~[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.web.context.request.AbstractRequestAttributesScope.get(AbstractRequestAttributesScope.java:41) ~[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:340) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]

我希望我的应用程序/微服务(使用@FeingClient调用另一个应用程序/微服务)成为无状态的。但是,我已经尝试了这两种方法,包括security.sessions=STATELESS (SpringBoot默认值)和security.sessions=ALWAYS (只是尝试一下)。在这两种情况下,我都得到了同样的例外。

在查看代码时,我看到OAuth2ClientContext保存在会话中(会话作用域bean)。当您想要实现无状态OAuth2启用的应用程序/微服务时,它是如何工作的?准确地说,这是在我当前的场景中使用OAuth2的最大优势之一。然而,正如我所说,结果是相同的使能会议。

有人能帮忙吗?

非常感谢!:)

EN

回答 3

Stack Overflow用户

发布于 2016-01-13 11:01:02

我发现问题在于Hystrix强制在另一个线程中执行代码,因此您无法访问请求/会话作用域bean。我使用@FeignClient并启用Hystrix。当我使用feign.hystrix.enabled: false禁用Hystrix时,从Microservice A到Microservice B的调用很好,中继令牌(使用OAuth2FeignRequestInterceptor)很好。

但是,希望能够使Hystrix启用。我在这篇文章中看到,在这方面,有一个新的模块改进了Hystrix伪装(伪装-hystrix模块):

Does Spring Cloud Feign client call execute inside hystrix command?

但是,我看不出如何正确地使用假冒伪劣的hystrix来完成设置,而且我也找不到一个例子。拜托,你能帮上忙还是用假冒伪劣来举个例子?

非常感谢!

票数 6
EN

Stack Overflow用户

发布于 2016-11-24 15:43:08

我不太确定我是否正确地理解了你,但以下几点对我是有帮助的。

请参阅https://jfconavarrete.wordpress.com/2014/09/15/make-spring-security-context-available-inside-a-hystrix-command/

基本上,本教程将展示如何使用额外的“插件”来设置/增强hystrix,以便通过线程局部变量在hystrix包装调用中提供安全上下文。

使用此设置,您只需定义一个伪请求拦截器,如下所示:

代码语言:javascript
复制
@Bean
public RequestInterceptor requestTokenBearerInterceptor() {

    return new RequestInterceptor() {
        @Override
        public void apply(RequestTemplate requestTemplate) {
            Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
            OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails) authentication.getDetails();
            requestTemplate.header("Authorization", "Bearer " + details.getTokenValue());                   
        }
    };
}

使用此设置,将请求中包含的令牌提供给假冒伪劣请求拦截器,这样您就可以使用经过身份验证的用户的令牌在假装请求上设置授权头。

还请注意,使用这种方法,您可以将SessionManagementStrategy保持为“无状态”,因为服务器端不需要“存储”任何数据。

票数 4
EN

Stack Overflow用户

发布于 2020-09-22 06:17:13

使用此代码并注释RESTEMPLATE配置,当您将其用作带状客户端时,我们将使用oauth2restTemplate

代码语言:javascript
复制
@EnableOAuth2Client
@Configuration
public class OAuthClientConfig {

    @Value("${config.oauth2.accessTokenUri}")
    private String tokenUri;

    @Value("${app.client.id}")
    private String clientId;

    @Value("${app.client.secret}")
    private String clientSecret;

    @Bean
    protected OAuth2ProtectedResourceDetails resource() {
        ResourceOwnerPasswordResourceDetails resource;
        resource = new ResourceOwnerPasswordResourceDetails();

        List<String> scopes = new ArrayList<String>(2);
        scopes.add("write");
        scopes.add("read");
        resource.setAccessTokenUri(tokenUri);
        resource.setClientId(clientId);
        resource.setClientSecret(clientSecret);
        resource.setGrantType("password");
        resource.setScope(scopes);
        return resource;
    }

    @Bean
    public OAuth2ClientContext oauth2ClientContext() {
        DefaultOAuth2ClientContext defaultOAuth2ClientContext = new DefaultOAuth2ClientContext();
        return defaultOAuth2ClientContext;
    }

    @Bean
    @Primary
    @LoadBalanced
    public OAuth2RestTemplate oAuth2RestTemplate(OAuth2ProtectedResourceDetails oAuth2ProtectedResourceDetails,
            OAuth2ClientContext oauth2ClientContext) {
        OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(oAuth2ProtectedResourceDetails, oauth2ClientContext);
        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
        restTemplate.setRequestFactory(factory);
        return restTemplate;
    }

    @Bean
    public OAuth2FeignRequestInterceptor aauthRequestInterceptor(OAuth2ProtectedResourceDetails oAuth2ProtectedResourceDetails,
            OAuth2ClientContext oauth2ClientContext)
    {
        OAuth2FeignRequestInterceptor auth2FeignRequestInterceptor=new OAuth2FeignRequestInterceptor(oauth2ClientContext, oAuth2ProtectedResourceDetails);
        return auth2FeignRequestInterceptor;
    }
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/34677470

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档