我的编程空间,编程开发者的网络收藏夹
学习永远不晚

springcloudoauth2feign遇到的坑及解决

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

springcloudoauth2feign遇到的坑及解决

spring cloud oauth2 feign 遇到的坑

关于oauth2相关的内容这里不重复描述,在spring cloud中在管理内部api时鉴权相信有很多人会有疑问,这里描述两种比较low的用法,由于公司内部使用的是阿里云edas这里仅仅是记录一下,如果有更好的用法在请赐教,不喜勿喷!

客户端模式

提供三方jar包

这里需要抽一个jar包,需要用到feign的为服务端直接利用maven模式引入feign即可

<dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-feign</artifactId>
        </dependency>
        <dependency>
            <groupId>com.netflix.feign</groupId>
            <artifactId>feign-okhttp</artifactId>
            <version>8.18.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-oauth2</artifactId>
        </dependency>
    </dependencies>

核心类

  • CustomHystrixConcurrencyStrategy.java
  • Oauth2ClientProperties.java
  • OAuth2FeignAutoConfiguration.java
  • OAuth2FeignRequestInterceptor.java

package com.paascloud.security.feign;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

@Data
@ConfigurationProperties(prefix = "paascloud.oauth2.client")
public class Oauth2ClientProperties {
    private String id;
    private String accessTokenUrl;
    private String clientId;
    private String clientSecret;
    private String clientAuthenticationScheme;
}
package com.paascloud.security.feign;
import com.netflix.hystrix.strategy.HystrixPlugins;
import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy;
import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;
import org.springframework.stereotype.Component;
import java.util.concurrent.Callable;

@Component
public class CustomHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy {
    
    public CustomHystrixConcurrencyStrategy() {
        HystrixPlugins.getInstance().registerConcurrencyStrategy(this);
    }
    
    @Override
    public <T> Callable<T> wrapCallable(Callable<T> callable) {
        return new HystrixContextWrapper<T>(callable);
    }
    
    public static class HystrixContextWrapper<V> implements Callable<V> {
        private HystrixRequestContext hystrixRequestContext;
        private Callable<V> delegate;
        
        HystrixContextWrapper(Callable<V> delegate) {
        this.hystrixRequestContext = HystrixRequestContext.getContextForCurrentThread();
            this.delegate = delegate;
        }
        
        @Override
        public V call() throws Exception {
            HystrixRequestContext existingState = HystrixRequestContext.getContextForCurrentThread();
            try {
                HystrixRequestContext.setContextOnCurrentThread(this.hystrixRequestContext);
                return this.delegate.call();
            } finally {
                HystrixRequestContext.setContextOnCurrentThread(existingState);
            }
        }
    }
}
package com.paascloud.security.feign;
import feign.Logger;
import feign.RequestInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.Netty4ClientHttpRequestFactory;
import org.springframework.security.oauth2.client.DefaultOAuth2ClientContext;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails;
import org.springframework.security.oauth2.common.AuthenticationScheme;

@Configuration
@EnableConfigurationProperties(Oauth2ClientProperties.class)
public class OAuth2FeignAutoConfiguration {
    private final Oauth2ClientProperties oauth2ClientProperties;
    
    @Autowired
    public OAuth2FeignAutoConfiguration(Oauth2ClientProperties oauth2ClientProperties) {
        this.oauth2ClientProperties = oauth2ClientProperties;
    }
    
    @Bean("paascloudClientCredentialsResourceDetails")
    public ClientCredentialsResourceDetails resourceDetails() {
        ClientCredentialsResourceDetails details = new ClientCredentialsResourceDetails();
        details.setId(oauth2ClientProperties.getId());
        details.setAccessTokenUri(oauth2ClientProperties.getAccessTokenUrl());
        details.setClientId(oauth2ClientProperties.getClientId());
        details.setClientSecret(oauth2ClientProperties.getClientSecret());
        details.setAuthenticationScheme(AuthenticationScheme.valueOf(oauth2ClientProperties.getClientAuthenticationScheme()));
        return details;
    }
    
    @Bean("paascloudOAuth2RestTemplate")
    public OAuth2RestTemplate oAuth2RestTemplate() {
        final OAuth2RestTemplate oAuth2RestTemplate = new OAuth2RestTemplate(resourceDetails(), new DefaultOAuth2ClientContext());
        oAuth2RestTemplate.setRequestFactory(new Netty4ClientHttpRequestFactory());
        return oAuth2RestTemplate;
    }
    
    @Bean
    public RequestInterceptor oauth2FeignRequestInterceptor(@Qualifier("paascloudOAuth2RestTemplate") OAuth2RestTemplate oAuth2RestTemplate) {
        return new OAuth2FeignRequestInterceptor(oAuth2RestTemplate);
    }
    
    @Bean
    Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }
}
package com.paascloud.security.feign;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.util.Assert;

public class OAuth2FeignRequestInterceptor implements RequestInterceptor {
    private static final String AUTHORIZATION_HEADER = "Authorization";
    private static final String BEARER_TOKEN_TYPE = "bearer";
    private final OAuth2RestTemplate oAuth2RestTemplate;
    
    OAuth2FeignRequestInterceptor(OAuth2RestTemplate oAuth2RestTemplate) {
        Assert.notNull(oAuth2RestTemplate, "Context can not be null");
        this.oAuth2RestTemplate = oAuth2RestTemplate;
    }
    
    @Override
    public void apply(RequestTemplate template) {
        template.header(AUTHORIZATION_HEADER, String.format("%s %s", BEARER_TOKEN_TYPE,  oAuth2RestTemplate.getAccessToken().toString()));
    }
}

调用端配置

引入maven依赖

<dependency>
            <groupId>com.liuzm.paascloud.common</groupId>
            <artifactId>paascloud-security-feign</artifactId>
            <version>1.0-SNAPSHOT</version>
</dependency>

@FeignClient加入configuration属性


@FeignClient(value = "paascloud-provider-mdc", configuration = OAuth2FeignAutoConfiguration.class, fallback = MdcProductFeignHystrix.class)
public interface MdcProductFeignApi {
    
    @RequestMapping(value = "/api/product/updateProductStockById", method = RequestMethod.POST)
    int updateProductStockById(@RequestBody ProductDto productDto);
}

认证服务器配置

@Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.withClientDetails(restClientDetailsService);
    }
package com.paascloud.provider.security;
import com.paascloud.security.core.properties.OAuth2ClientProperties;
import com.paascloud.security.core.properties.SecurityProperties;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.oauth2.config.annotation.builders.InMemoryClientDetailsServiceBuilder;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.ClientRegistrationException;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;

@Component("restClientDetailsService")
public class RestClientDetailsServiceImpl implements ClientDetailsService {
    private ClientDetailsService clientDetailsService;
    @Autowired
    private SecurityProperties securityProperties;
    
    @PostConstruct
    public void init() {
        InMemoryClientDetailsServiceBuilder builder = new InMemoryClientDetailsServiceBuilder();
        if (ArrayUtils.isNotEmpty(securityProperties.getOauth2().getClients())) {
            for (OAuth2ClientProperties client : securityProperties.getOauth2().getClients()) {
                builder.withClient(client.getClientId())
                        .secret(client.getClientSecret())
                        .authorizedGrantTypes("refresh_token", "password", "client_credentials")
                        .accessTokenValiditySeconds(client.getAccessTokenValidateSeconds())
                        .refreshTokenValiditySeconds(2592000)
                        .scopes(client.getScope());
            }
        }
        try {
            clientDetailsService = builder.build();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    @Override
    public ClientDetails loadClientByClientId(String clientId) throws ClientRegistrationException {
        return  clientDetailsService.loadClientByClientId(clientId);
    }
}

bootstrap.yml配置

security:
    oauth2:
      tokenStore: jwt
      clients[0]:
        clientId: paascloud-client-uac
        clientSecret: paascloudClientSecret
        accessTokenValidateSeconds: 7200
        scope: "*"
      clients[1]:
        clientId: paascloud-browser
        clientSecret: paascloudClientSecret
        accessTokenValidateSeconds: 7200
        scope: "*"
      clients[2]:
        clientId: paascloud-client-gateway
        clientSecret: paascloudClientSecret
        accessTokenValidateSeconds: 7200
        scope: "*"
      clients[3]:
        clientId: paascloud-client-zipkin
        clientSecret: paascloudClientSecret
        accessTokenValidateSeconds: 7200
        scope: "*"
      clients[4]:
        clientId: paascloud-client-mdc
        clientSecret: paascloudClientSecret
        accessTokenValidateSeconds: 7200
        scope: "*"
      clients[5]:
        clientId: paascloud-client-omc
        clientSecret: paascloudClientSecret
        accessTokenValidateSeconds: 7200
        scope: "*"
      clients[6]:
        clientId: paascloud-client-opc
        clientSecret: paascloudClientSecret
        accessTokenValidateSeconds: 7200
        scope: "*"

到此客户端模式配置完成!

基于spring security

开放权限,利用url规范来规划客户端的url不通过auth2鉴权,这里唯一的区别是在feign拦截器里处理的逻辑改一下,代码如下

@Autowired
private OAuth2ClientContext context;
@Override
    public void apply(RequestTemplate template) {
        if(context.getAccessToken() != null && context.getAccessToken().getValue() != null && OAuth2AccessToken.BEARER_TYPE.equalsIgnoreCase(context.getAccessToken().getTokenType()) ){
            template.header("Authorization", String.format("%s %s", OAuth2AccessToken.BEARER_TYPE, context.getAccessToken().getValue()));
        }
    }

spring cloud微服务增加oauth2权限后 feign调用报null

在授权服务里,用户通过用户名密码,或者手机和验证码等方式登陆之后,在http头里会有授权的标识,在客户端调用时,需要添加当时有效的token才可以正常访问被授权的页面。

Content-Type:application/json
Authorization:Bearer d79c064c-8675-4047-a119-fac692e447e8

而在业务层里,服务与服务之间使用feign来实现调用,而授权的代码我们可以通过拦截器实现,在feign请求之前,把当前服务的token添加到目标服务的请求头就可以了

一般是这样实现的


@Component
public class TokenFeignClientInterceptor implements RequestInterceptor {
  
  @Override
  public void apply(RequestTemplate requestTemplate) {
    RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
    if (requestAttributes != null) {
      HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
      requestTemplate.header("Authorization", request.getHeader("Authorization"));
    }
  }
}

上面的拦截器代码没有什么问题,也很好理解,但事实上,当你的feign开启了hystrix功能,如果开启了,需要把hystrix的策略进行修改,默认是THREAD的,这个级别时ThreadLocal是空的,所以你的授权不能传给feign的拦截器.

hystrix: 
    command: 
        default: 
            execution: 
                isolation: 
                    strategy: SEMAPHORE 

以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

springcloudoauth2feign遇到的坑及解决

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

开启Selinux遇到的坑及解决

这篇文章详细介绍了开启SELinux时可能遇到的常见问题和解决办法,包括:selinuxfs未挂载、策略不兼容、更新问题、上下文不正确、布尔值错误配置、审计记录已满、权限拒绝和导致系统无法启动。本文提供了针对每个问题的具体解决方案,包括挂载selinuxfs、检查策略、强制安装更新、设置正确上下文、修改布尔值、增加队列大小、授予权限和禁用SELinux。
开启Selinux遇到的坑及解决
2024-04-02

使用SpringBoot的CommandLineRunner遇到的坑及解决

这篇文章主要介绍了使用SpringBoot的CommandLineRunner遇到的坑及解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
2023-02-13

vue3+vite2+mqtt连接遇到的坑及解决

这篇文章主要介绍了vue3+vite2+mqtt连接遇到的坑及解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
2023-05-17

Golang解析JSON遇到的坑及解决方法

这篇文章主要为大家介绍了Golang解析JSON时会遇到的一些坑及解决方法,文中的示例代码讲解详细,对我们学习Go语言有一点的帮助,需要的可以参考一下
2023-02-26

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录