本篇内容主要讲解“spring cloud oauth2 feign遇到的坑怎么解决”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“spring cloud oauth2 feign遇到的坑怎么解决”吧!
spring cloud oauth3 feign 遇到的坑
关于oauth3相关的内容这里不重复描述,在spring cloud中在管理内部api时鉴权相信有很多人会有疑问,这里描述两种比较low的用法。
客户端模式
提供三方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-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;@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;@Componentpublic 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.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;@Configuration@EnableConfigurationProperties(Oauth3ClientProperties.class)public class OAuth3FeignAutoConfiguration { private final Oauth3ClientProperties oauth3ClientProperties; @Autowired public OAuth3FeignAutoConfiguration(Oauth3ClientProperties oauth3ClientProperties) { this.oauth3ClientProperties = oauth3ClientProperties; } @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; } @Bean("paascloudOAuth3RestTemplate") public OAuth3RestTemplate oAuth3RestTemplate() { final OAuth3RestTemplate oAuth3RestTemplate = new OAuth3RestTemplate(resourceDetails(), new DefaultOAuth3ClientContext()); oAuth3RestTemplate.setRequestFactory(new Netty4ClientHttpRequestFactory()); return oAuth3RestTemplate; } @Bean public RequestInterceptor oauth3FeignRequestInterceptor(@Qualifier("paascloudOAuth3RestTemplate") OAuth3RestTemplate oAuth3RestTemplate) { return new OAuth3FeignRequestInterceptor(oAuth3RestTemplate); } @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;public class OAuth3FeignRequestInterceptor implements RequestInterceptor { private static final String AUTHORIZATION_HEADER = "Authorization"; private static final String BEARER_TOKEN_TYPE = "bearer"; private final OAuth3RestTemplate oAuth3RestTemplate; OAuth3FeignRequestInterceptor(OAuth3RestTemplate oAuth3RestTemplate) { Assert.notNull(oAuth3RestTemplate, "Context can not be null"); this.oAuth3RestTemplate = oAuth3RestTemplate; } @Override public void apply(RequestTemplate template) { template.header(AUTHORIZATION_HEADER, String.format("%s %s", BEARER_TOKEN_TYPE, oAuth3RestTemplate.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 = OAuth3FeignAutoConfiguration.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.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;@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.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(); } } @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
开放权限,利用url规范来规划客户端的url不通过auth3鉴权,这里唯一的区别是在feign拦截器里处理的逻辑改一下,代码如下
@Autowiredprivate 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微服务增加oauth3权限后 feign调用报null
在授权服务里,用户通过用户名密码,或者手机和验证码等方式登陆之后,在http头里会有授权的标识,在客户端调用时,需要添加当时有效的token才可以正常访问被授权的页面。
Content-Type:application/jsonAuthorization:Bearer d79c064c-8675-4047-a119-fac692e447e8
而在业务层里,服务与服务之间使用feign来实现调用,而授权的代码我们可以通过拦截器实现,在feign请求之前,把当前服务的token添加到目标服务的请求头就可以了
一般是这样实现的
@Componentpublic 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
到此,相信大家对“spring cloud oauth2 feign遇到的坑怎么解决”有了更深的了解,不妨来实际操作一番吧!这里是编程网网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!