spring cloud oauth2 feign 遇到的坑及解决

网友投稿 411 2022-08-23


spring cloud oauth2 feign 遇到的坑及解决

目录springcloudoauth2feign遇到的坑客户端模式基于springsecurityspringcloud微服务增加oauth2权限后feign调用报null一般是这样实现的

spring cloud oauth2 feign 遇到的坑

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

客户端模式

提供三方jar包

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

org.springframework.cloud

spring-cloud-starter-feign

com.netflix.feign

feign-okhttp

8.18.0

org.springframework.cloud

spring-cloud-starter-oauth2

核心类

CustomHystrixConcurrencyStrategy.javaOauth2ClientProperties.javaOAuth2FeignAutoConfiguration.javaOAuth2FeignRequestInterceptor.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.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;

/**

* 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 the type parameter

* @param callable the callable

*

* @return the callable

*/

@Override

public Callable wrapCallable(Callable callable) {

return new HystrixContextWrapper(callable);

}

/**

* The class Hystrix context wrapper.

*

* @param the type parameter

*

* @author paascloud.net @gmail.com

*/

public static class HystrixContextWrapper implements Callable {

private HystrixRequestContext hystrixRequestContext;

private Callable delegate;

/**

* Instantiates a new Hystrix context wrapper.

*

* @param delegate the delegate

*/

HystrixContextWrapper(Callable 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.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;

/**

* The class O auth 2 feign auto configuration.

*

* @author paascloud.net @gmail.com

*/

@Configuration

@EnableConfigurationProperties(Oauth2ClientProperties.class)

public class OAuth2FeignAutoConfiguration {

private final Oauth2ClientProperties oauth2ClientProperties;

/**

* Instantiates a new O auth 2 feign auto configuration.

*

* @param oauth2ClientProperties the oauth 2 client properties

*/

@Autowired

public OAuth2FeignAutoConfiguration(Oauth2ClientProperties oauth2ClientProperties) {

this.oauth2ClientProperties = oauth2ClientProperties;

}

/**

* Resource details client credentials resource details.

*

* @return the client credentials resource details

*/

@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;

}

/**

* O auth 2 rest template o auth 2 rest template.

*

* @return the o auth 2 rest template

*/

@Bean("paascloudOAuth2RestTemplate")

public OAuth2RestTemplate oAuth2RestTemplate() {

final OAuth2RestTemplate oAuth2RestTemplate = new OAuth2RestTemplate(resourceDetails(), new DefaultOAuth2ClientContext());

oAuth2RestTemplate.setRequestFactory(new Netty4ClientHttpRequestFactory());

return oAuth2RestTemplate;

}

/**

* Oauth 2 feign request interceptor request interceptor.

*

* @param oAuth2RestTemplate the o auth 2 rest template

*

* @return the request interceptor

*/

@Bean

public RequestInterceptor oauth2FeignRequestInterceptor(@Qualifier("paascloudOAuth2RestTemplate") OAuth2RestTemplate oAuth2RestTemplate) {

return new OAuth2FeignRequestInterceptor(oAuth2RestTemplate);

}

/**

* 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.oauth2.client.OAuth2RestTemplate;

import org.springframework.util.Assert;

/**

* The class O auth 2 feign request interceptor.

*

* @author paascloud.net @gmail.com

*/

public class OAuth2FeignRequestInterceptor implements RequestInterceptor {

private static final String AUTHORIZATION_HEADER = "Authorization";

private static final String BEARER_TOKEN_TYPE = "bearer";

private final OAuth2RestTemplate oAuth2RestTemplate;

/**

* Instantiates a new O auth 2 feign request interceptor.

*

* @param oAuth2RestTemplate the o auth 2 rest template

*/

OAuth2FeignRequestInterceptor(OAuth2RestTemplate oAuth2RestTemplate) {

Assert.notNull(oAuth2RestTemplate, "Context can not be null");

this.oAuth2RestTemplate = oAuth2RestTemplate;

}

/**

* Apply.

*

* @param template the template

*/

@Override

public void apply(RequestTemplate template) {

template.header(AUTHORIZATION_HEADER, String.format("%s %s", BEARER_TOKEN_TYPE, oAuth2RestTemplate.getAccessToken().toString()));

}

}

调用端配置

引入maven依赖

com.liuzm.paascloud.common

paascloud-security-feign

1.0-SNAPSHOT

@FeignClient加入configuration属性

/**

* The interface Mdc product feign api.

* @author paascloud.net@gmail.com

*/

@FeignClient(value = "paascloud-provider-mdc", configuration = OAuth2FeignAutoConfiguration.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);

}

认证服务器配置

@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;

/**

* 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.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();

}

}

/**

* 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:

oauth2:

tokenStore: jwt

cliehttp://nts[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添加到目标服务的请求头就可以了

一般是这样实现的

/**

* 发送FeignClient设置Header信息.

* http://itmuch.com/spring-cloud-sum/hystrix-threadlocal/

* Hystrix传播ThreadLocal对象

*/

@Component

public class TokenFeignClientInterceptor implements RequestInterceptor {

/**

* token放在请求头.

*

* @param requestTemplate 请求参数

*/

@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


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:9个应知应会的单行Python代码(一行python代码)
下一篇:python3基础:变量与常用数据类型(在python3中标准数据类型包括)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~