溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

spring?cloud?oauth2?feign遇到的坑怎么解決

發(fā)布時間:2022-03-07 16:31:06 來源:億速云 閱讀:166 作者:iii 欄目:開發(fā)技術(shù)

本篇內(nèi)容主要講解“spring cloud oauth2 feign遇到的坑怎么解決”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學(xué)習(xí)“spring cloud oauth2 feign遇到的坑怎么解決”吧!

spring cloud oauth3 feign 遇到的坑

關(guān)于oauth3相關(guān)的內(nèi)容這里不重復(fù)描述,在spring cloud中在管理內(nèi)部api時鑒權(quán)相信有很多人會有疑問,這里描述兩種比較low的用法。

客戶端模式

提供三方j(luò)ar包

spring?cloud?oauth2?feign遇到的坑怎么解決

這里需要抽一個jar包,需要用到feign的為服務(wù)端直接利用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-oauth3</artifactId>
        </dependency>
    </dependencies>

核心類

  • CustomHystrixConcurrencyStrategy.java

  • Oauth3ClientProperties.java

  • OAuth3FeignAutoConfiguration.java

  • OAuth3FeignRequestInterceptor.java

package com.paascloud.security.feign;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
 * The class Oauth 2 client properties.
 *
 * @author paascloud.net @gmail.com
 */
@Data
@ConfigurationProperties(prefix = "paascloud.oauth3.client")
public class Oauth3ClientProperties {
    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;
/**
 * The class Custom hystrix concurrency strategy.
 *
 * @author paascloud.net @gmail.com
 */
@Component
public class CustomHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy {
    /**
     * Instantiates a new Custom hystrix concurrency strategy.
     */
    public CustomHystrixConcurrencyStrategy() {
        HystrixPlugins.getInstance().registerConcurrencyStrategy(this);
    }
    /**
     * Wrap callable callable.
     *
     * @param <T>      the type parameter
     * @param callable the callable
     *
     * @return the callable
     */
    @Override
    public <T> Callable<T> wrapCallable(Callable<T> callable) {
        return new HystrixContextWrapper<T>(callable);
    }
    /**
     * The class Hystrix context wrapper.
     *
     * @param <V> the type parameter
     *
     * @author paascloud.net @gmail.com
     */
    public static class HystrixContextWrapper<V> implements Callable<V> {
        private HystrixRequestContext hystrixRequestContext;
        private Callable<V> delegate;
        /**
         * Instantiates a new Hystrix context wrapper.
         *
         * @param delegate the delegate
         */
        HystrixContextWrapper(Callable<V> delegate) {
        this.hystrixRequestContext = HystrixRequestContext.getContextForCurrentThread();
            this.delegate = delegate;
        }
        /**
         * Call v.
         *
         * @return the v
         *
         * @throws Exception the exception
         */
        @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.oauth3.client.DefaultOAuth3ClientContext;
import org.springframework.security.oauth3.client.OAuth3RestTemplate;
import org.springframework.security.oauth3.client.token.grant.client.ClientCredentialsResourceDetails;
import org.springframework.security.oauth3.common.AuthenticationScheme;
/**
 * The class O auth 2 feign auto configuration.
 *
 * @author paascloud.net @gmail.com
 */
@Configuration
@EnableConfigurationProperties(Oauth3ClientProperties.class)
public class OAuth3FeignAutoConfiguration {
    private final Oauth3ClientProperties oauth3ClientProperties;
    /**
     * Instantiates a new O auth 2 feign auto configuration.
     *
     * @param oauth3ClientProperties the oauth 2 client properties
     */
    @Autowired
    public OAuth3FeignAutoConfiguration(Oauth3ClientProperties oauth3ClientProperties) {
        this.oauth3ClientProperties = oauth3ClientProperties;
    }
    /**
     * Resource details client credentials resource details.
     *
     * @return the client credentials resource details
     */
    @Bean("paascloudClientCredentialsResourceDetails")
    public ClientCredentialsResourceDetails resourceDetails() {
        ClientCredentialsResourceDetails details = new ClientCredentialsResourceDetails();
        details.setId(oauth3ClientProperties.getId());
        details.setAccessTokenUri(oauth3ClientProperties.getAccessTokenUrl());
        details.setClientId(oauth3ClientProperties.getClientId());
        details.setClientSecret(oauth3ClientProperties.getClientSecret());
        details.setAuthenticationScheme(AuthenticationScheme.valueOf(oauth3ClientProperties.getClientAuthenticationScheme()));
        return details;
    }
    /**
     * O auth 2 rest template o auth 2 rest template.
     *
     * @return the o auth 2 rest template
     */
    @Bean("paascloudOAuth3RestTemplate")
    public OAuth3RestTemplate oAuth3RestTemplate() {
        final OAuth3RestTemplate oAuth3RestTemplate = new OAuth3RestTemplate(resourceDetails(), new DefaultOAuth3ClientContext());
        oAuth3RestTemplate.setRequestFactory(new Netty4ClientHttpRequestFactory());
        return oAuth3RestTemplate;
    }
    /**
     * Oauth 2 feign request interceptor request interceptor.
     *
     * @param oAuth3RestTemplate the o auth 2 rest template
     *
     * @return the request interceptor
     */
    @Bean
    public RequestInterceptor oauth3FeignRequestInterceptor(@Qualifier("paascloudOAuth3RestTemplate") OAuth3RestTemplate oAuth3RestTemplate) {
        return new OAuth3FeignRequestInterceptor(oAuth3RestTemplate);
    }
    /**
     * Feign logger level logger . level.
     *
     * @return the logger . level
     */
    @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.oauth3.client.OAuth3RestTemplate;
import org.springframework.util.Assert;
/**
 * The class O auth 2 feign request interceptor.
 *
 * @author paascloud.net @gmail.com
 */
public class OAuth3FeignRequestInterceptor implements RequestInterceptor {
    private static final String AUTHORIZATION_HEADER = "Authorization";
    private static final String BEARER_TOKEN_TYPE = "bearer";
    private final OAuth3RestTemplate oAuth3RestTemplate;
    /**
     * Instantiates a new O auth 2 feign request interceptor.
     *
     * @param oAuth3RestTemplate the o auth 2 rest template
     */
    OAuth3FeignRequestInterceptor(OAuth3RestTemplate oAuth3RestTemplate) {
        Assert.notNull(oAuth3RestTemplate, "Context can not be null");
        this.oAuth3RestTemplate = oAuth3RestTemplate;
    }
    /**
     * Apply.
     *
     * @param template the template
     */
    @Override
    public void apply(RequestTemplate template) {
        template.header(AUTHORIZATION_HEADER, String.format("%s %s", BEARER_TOKEN_TYPE,  oAuth3RestTemplate.getAccessToken().toString()));
    }
}

調(diào)用端配置

引入maven依賴

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

@FeignClient加入configuration屬性

/**
 * The interface Mdc product feign api.
 * @author paascloud.net@gmail.com
 */
@FeignClient(value = "paascloud-provider-mdc", configuration = OAuth3FeignAutoConfiguration.class, fallback = MdcProductFeignHystrix.class)
public interface MdcProductFeignApi {
    /**
     * Update product stock by id int.
     *
     * @param productDto the product dto
     *
     * @return the int
     */
    @RequestMapping(value = "/api/product/updateProductStockById", method = RequestMethod.POST)
    int updateProductStockById(@RequestBody ProductDto productDto);
}

認(rèn)證服務(wù)器配置

@Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.withClientDetails(restClientDetailsService);
    }
package com.paascloud.provider.security;
import com.paascloud.security.core.properties.OAuth3ClientProperties;
import com.paascloud.security.core.properties.SecurityProperties;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.oauth3.config.annotation.builders.InMemoryClientDetailsServiceBuilder;
import org.springframework.security.oauth3.provider.ClientDetails;
import org.springframework.security.oauth3.provider.ClientDetailsService;
import org.springframework.security.oauth3.provider.ClientRegistrationException;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
/**
 * The class Rest client details service.
 *
 * @author paascloud.net @gmail.com
 */
@Component("restClientDetailsService")
public class RestClientDetailsServiceImpl implements ClientDetailsService {
    private ClientDetailsService clientDetailsService;
    @Autowired
    private SecurityProperties securityProperties;
    /**
     * Init.
     */
    @PostConstruct
    public void init() {
        InMemoryClientDetailsServiceBuilder builder = new InMemoryClientDetailsServiceBuilder();
        if (ArrayUtils.isNotEmpty(securityProperties.getOauth3().getClients())) {
            for (OAuth3ClientProperties client : securityProperties.getOauth3().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();
        }
    }
    /**
     * Load client by client id client details.
     *
     * @param clientId the client id
     *
     * @return the client details
     *
     * @throws ClientRegistrationException the client registration exception
     */
    @Override
    public ClientDetails loadClientByClientId(String clientId) throws ClientRegistrationException {
        return  clientDetailsService.loadClientByClientId(clientId);
    }
}

bootstrap.yml配置

security:
    oauth3:
      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

開放權(quán)限,利用url規(guī)范來規(guī)劃客戶端的url不通過auth3鑒權(quán),這里唯一的區(qū)別是在feign攔截器里處理的邏輯改一下,代碼如下

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

spring cloud微服務(wù)增加oauth3權(quán)限后 feign調(diào)用報null

在授權(quán)服務(wù)里,用戶通過用戶名密碼,或者手機(jī)和驗證碼等方式登陸之后,在http頭里會有授權(quán)的標(biāo)識,在客戶端調(diào)用時,需要添加當(dāng)時有效的token才可以正常訪問被授權(quán)的頁面。

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

而在業(yè)務(wù)層里,服務(wù)與服務(wù)之間使用feign來實現(xiàn)調(diào)用,而授權(quán)的代碼我們可以通過攔截器實現(xiàn),在feign請求之前,把當(dāng)前服務(wù)的token添加到目標(biāo)服務(wù)的請求頭就可以了

一般是這樣實現(xiàn)的

/**
 * 發(fā)送FeignClient設(shè)置Header信息.
 * http://www.itmuch.com/spring-cloud-sum/hystrix-threadlocal/
 * Hystrix傳播ThreadLocal對象
 */
@Component
public class TokenFeignClientInterceptor implements RequestInterceptor {
  /**
   * token放在請求頭.
   *
   * @param requestTemplate 請求參數(shù)
   */
  @Override
  public void apply(RequestTemplate requestTemplate) {
    RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
    if (requestAttributes != null) {
      HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
      requestTemplate.header("Authorization", request.getHeader("Authorization"));
    }
  }
}

上面的攔截器代碼沒有什么問題,也很好理解,但事實上,當(dāng)你的feign開啟了hystrix功能,如果開啟了,需要把hystrix的策略進(jìn)行修改,默認(rèn)是THREAD的,這個級別時ThreadLocal是空的,所以你的授權(quán)不能傳給feign的攔截器.

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

到此,相信大家對“spring cloud oauth2 feign遇到的坑怎么解決”有了更深的了解,不妨來實際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI