diff --git a/mall-ebtp-cloud-feign-starter/pom.xml b/mall-ebtp-cloud-feign-starter/pom.xml
index 7623cfd..7bb8c1e 100644
--- a/mall-ebtp-cloud-feign-starter/pom.xml
+++ b/mall-ebtp-cloud-feign-starter/pom.xml
@@ -8,7 +8,7 @@
com.chinaunicom.ebtp
mall-ebtp-cloud-parent
0.0.1
- ../mall-ebtp-cloud-parent
+
com.chinaunicom.ebtp
mall-ebtp-cloud-feign-starter
@@ -16,14 +16,18 @@
mall-ebtp-cloud-feign-starter
-
- org.springframework.cloud
- spring-cloud-starter-openfeign
-
-
- io.github.openfeign
- feign-okhttp
-
+
+ org.springframework.cloud
+ spring-cloud-starter-openfeign
+
+
+ org.springframework.cloud
+ spring-cloud-netflix-hystrix
+
+
+ io.github.openfeign
+ feign-okhttp
+
-
+
diff --git a/mall-ebtp-cloud-feign-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/feign/starter/FeignStarterConfiguration.java b/mall-ebtp-cloud-feign-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/feign/starter/FeignStarterConfiguration.java
index 89a34bc..39d56f9 100644
--- a/mall-ebtp-cloud-feign-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/feign/starter/FeignStarterConfiguration.java
+++ b/mall-ebtp-cloud-feign-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/feign/starter/FeignStarterConfiguration.java
@@ -1,10 +1,12 @@
package com.chinaunicom.mall.ebtp.cloud.feign.starter;
+import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
@Configuration
@PropertySource("classpath:feign-configuration.properties")
+@ComponentScan(basePackages = "com.chinaunicom.mall.ebtp.cloud.feign.starter")
public class FeignStarterConfiguration {
}
diff --git a/mall-ebtp-cloud-feign-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/feign/starter/HystrixSecurityAutoConfiguration.java b/mall-ebtp-cloud-feign-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/feign/starter/HystrixSecurityAutoConfiguration.java
new file mode 100644
index 0000000..44e4dc5
--- /dev/null
+++ b/mall-ebtp-cloud-feign-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/feign/starter/HystrixSecurityAutoConfiguration.java
@@ -0,0 +1,57 @@
+package com.chinaunicom.mall.ebtp.cloud.feign.starter;
+
+import javax.annotation.PostConstruct;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.AllNestedConditions;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.cloud.netflix.hystrix.security.SecurityContextConcurrencyStrategy;
+import org.springframework.context.annotation.Conditional;
+import org.springframework.context.annotation.Configuration;
+
+import com.chinaunicom.mall.ebtp.cloud.feign.starter.HystrixSecurityAutoConfiguration.HystrixSecurityCondition;
+import com.netflix.hystrix.Hystrix;
+import com.netflix.hystrix.strategy.HystrixPlugins;
+import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy;
+import com.netflix.hystrix.strategy.eventnotifier.HystrixEventNotifier;
+import com.netflix.hystrix.strategy.executionhook.HystrixCommandExecutionHook;
+import com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisher;
+import com.netflix.hystrix.strategy.properties.HystrixPropertiesStrategy;
+
+@Configuration
+@Conditional(HystrixSecurityCondition.class)
+@ConditionalOnClass({ Hystrix.class })
+public class HystrixSecurityAutoConfiguration {
+
+ private @Autowired HystrixConcurrencyStrategy requestAttributeHystrixConcurrencyStrategy;
+
+ @PostConstruct
+ public void init() {
+ HystrixEventNotifier eventNotifier = HystrixPlugins.getInstance().getEventNotifier();
+ HystrixMetricsPublisher metricsPublisher = HystrixPlugins.getInstance().getMetricsPublisher();
+ HystrixPropertiesStrategy propertiesStrategy = HystrixPlugins.getInstance().getPropertiesStrategy();
+ HystrixCommandExecutionHook commandExecutionHook = HystrixPlugins.getInstance().getCommandExecutionHook();
+
+ HystrixPlugins.reset();
+
+ HystrixPlugins.getInstance().registerConcurrencyStrategy(
+ new SecurityContextConcurrencyStrategy(requestAttributeHystrixConcurrencyStrategy));
+ HystrixPlugins.getInstance().registerEventNotifier(eventNotifier);
+ HystrixPlugins.getInstance().registerMetricsPublisher(metricsPublisher);
+ HystrixPlugins.getInstance().registerPropertiesStrategy(propertiesStrategy);
+ HystrixPlugins.getInstance().registerCommandExecutionHook(commandExecutionHook);
+ }
+
+ static class HystrixSecurityCondition extends AllNestedConditions {
+
+ public HystrixSecurityCondition() {
+ super(ConfigurationPhase.REGISTER_BEAN);
+ }
+
+ @ConditionalOnProperty(name = "hystrix.shareSecurityContext")
+ static class ShareSecurityContext {
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/mall-ebtp-cloud-feign-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/feign/starter/RequestAttributeHystrixConcurrencyStrategy.java b/mall-ebtp-cloud-feign-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/feign/starter/RequestAttributeHystrixConcurrencyStrategy.java
new file mode 100644
index 0000000..03e453e
--- /dev/null
+++ b/mall-ebtp-cloud-feign-starter/src/main/java/com/chinaunicom/mall/ebtp/cloud/feign/starter/RequestAttributeHystrixConcurrencyStrategy.java
@@ -0,0 +1,163 @@
+package com.chinaunicom.mall.ebtp.cloud.feign.starter;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+import org.springframework.stereotype.Component;
+import org.springframework.web.context.request.RequestAttributes;
+import org.springframework.web.context.request.RequestContextHolder;
+
+import com.netflix.hystrix.HystrixThreadPoolKey;
+import com.netflix.hystrix.HystrixThreadPoolProperties;
+import com.netflix.hystrix.strategy.HystrixPlugins;
+import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy;
+import com.netflix.hystrix.strategy.concurrency.HystrixRequestVariable;
+import com.netflix.hystrix.strategy.concurrency.HystrixRequestVariableLifecycle;
+import com.netflix.hystrix.strategy.eventnotifier.HystrixEventNotifier;
+import com.netflix.hystrix.strategy.executionhook.HystrixCommandExecutionHook;
+import com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisher;
+import com.netflix.hystrix.strategy.properties.HystrixPropertiesStrategy;
+import com.netflix.hystrix.strategy.properties.HystrixProperty;
+
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * 为了解决熔断器开启后, RequestInterceptor无法注入header的问题 ( Hystrix有隔离策略:THREAD以 及
+ * SEMAPHORE, thread策略会导致SecurityContext及RequestContext无法获取当前上下文, 因其实线程隔离的 )
+ *
+ * @author Ajaxfan
+ */
+@Slf4j
+@Component("requestAttributeHystrixConcurrencyStrategy")
+public class RequestAttributeHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy {
+
+ private HystrixConcurrencyStrategy delegate;
+
+ public RequestAttributeHystrixConcurrencyStrategy() {
+ init();
+ }
+
+ /**
+ * @param
+ * @param callable
+ * @return
+ */
+ @Override
+ public Callable wrapCallable(Callable callable) {
+ return new WrappedCallable<>(callable, RequestContextHolder.getRequestAttributes());
+ }
+
+ /**
+ * @param threadPoolKey
+ * @param corePoolSize
+ * @param maximumPoolSize
+ * @param keepAliveTime
+ * @param unit
+ * @param workQueue
+ * @return
+ */
+ @Override
+ public ThreadPoolExecutor getThreadPool(HystrixThreadPoolKey threadPoolKey, HystrixProperty corePoolSize,
+ HystrixProperty maximumPoolSize, HystrixProperty keepAliveTime, TimeUnit unit,
+ BlockingQueue workQueue) {
+ return this.delegate.getThreadPool(threadPoolKey, corePoolSize, maximumPoolSize, keepAliveTime, unit,
+ workQueue);
+ }
+
+ /**
+ * @param threadPoolKey
+ * @param threadPoolProperties
+ * @return
+ */
+ @Override
+ public ThreadPoolExecutor getThreadPool(HystrixThreadPoolKey threadPoolKey,
+ HystrixThreadPoolProperties threadPoolProperties) {
+ return this.delegate.getThreadPool(threadPoolKey, threadPoolProperties);
+ }
+
+ /**
+ * @param maxQueueSize
+ * @return
+ */
+ @Override
+ public BlockingQueue getBlockingQueue(int maxQueueSize) {
+ return this.delegate.getBlockingQueue(maxQueueSize);
+ }
+
+ /**
+ * @param
+ * @param rv
+ * @return
+ */
+ @Override
+ public HystrixRequestVariable getRequestVariable(HystrixRequestVariableLifecycle rv) {
+ return this.delegate.getRequestVariable(rv);
+ }
+
+ /**
+ * @author Ajaxfan
+ *
+ * @param
+ */
+ static class WrappedCallable implements Callable {
+ private final Callable target;
+ private final RequestAttributes requestAttributes;
+
+ public WrappedCallable(Callable target, RequestAttributes requestAttributes) {
+ this.target = target;
+ this.requestAttributes = requestAttributes;
+ }
+
+ @Override
+ public T call() throws Exception {
+ try {
+ RequestContextHolder.setRequestAttributes(requestAttributes);
+ return target.call();
+ } finally {
+ RequestContextHolder.resetRequestAttributes();
+ }
+ }
+ }
+
+ /**
+ * 初始化隔离器
+ */
+ private void init() {
+ try {
+ this.delegate = HystrixPlugins.getInstance().getConcurrencyStrategy();
+ if (this.delegate instanceof RequestAttributeHystrixConcurrencyStrategy) {
+ return;
+ }
+ HystrixCommandExecutionHook commandExecutionHook = HystrixPlugins.getInstance().getCommandExecutionHook();
+ HystrixEventNotifier eventNotifier = HystrixPlugins.getInstance().getEventNotifier();
+ HystrixMetricsPublisher metricsPublisher = HystrixPlugins.getInstance().getMetricsPublisher();
+ HystrixPropertiesStrategy propertiesStrategy = HystrixPlugins.getInstance().getPropertiesStrategy();
+ this.logCurrentStateOfHystrixPlugins(eventNotifier, metricsPublisher, propertiesStrategy);
+ HystrixPlugins.reset();
+ HystrixPlugins.getInstance().registerConcurrencyStrategy(this);
+ HystrixPlugins.getInstance().registerCommandExecutionHook(commandExecutionHook);
+ HystrixPlugins.getInstance().registerEventNotifier(eventNotifier);
+ HystrixPlugins.getInstance().registerMetricsPublisher(metricsPublisher);
+ HystrixPlugins.getInstance().registerPropertiesStrategy(propertiesStrategy);
+ } catch (Exception e) {
+ log.error("Failed to register Sleuth Hystrix Concurrency Strategy", e);
+ }
+ }
+
+ /**
+ * 生产当前隔离参数日志
+ *
+ * @param eventNotifier
+ * @param metricsPublisher
+ * @param propertiesStrategy
+ */
+ private void logCurrentStateOfHystrixPlugins(HystrixEventNotifier eventNotifier,
+ HystrixMetricsPublisher metricsPublisher, HystrixPropertiesStrategy propertiesStrategy) {
+ log.debug("Current Hystrix plugins configuration is [" + "concurrencyStrategy [" + this.delegate + "],"
+ + "eventNotifier [" + eventNotifier + "]," + "metricPublisher [" + metricsPublisher + "],"
+ + "propertiesStrategy [" + propertiesStrategy + "]," + "]");
+ log.debug("Registering Sleuth Hystrix Concurrency Strategy.");
+ }
+}
diff --git a/uboot-common/src/main/java/com/chinaunicom/mall/ebtp/common/config/FeignConfig.java b/uboot-common/src/main/java/com/chinaunicom/mall/ebtp/common/config/FeignConfig.java
index d2be1a7..ddef51d 100644
--- a/uboot-common/src/main/java/com/chinaunicom/mall/ebtp/common/config/FeignConfig.java
+++ b/uboot-common/src/main/java/com/chinaunicom/mall/ebtp/common/config/FeignConfig.java
@@ -1,9 +1,13 @@
package com.chinaunicom.mall.ebtp.common.config;
+import static com.chinaunicom.mall.ebtp.cloud.security.starter.common.Constants.AUTHORIZATION_HEADER;
+import static com.chinaunicom.mall.ebtp.cloud.security.starter.common.Constants.TOKEN_PREFIX;
+
+import org.apache.commons.lang3.RegExUtils;
+import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Configuration;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.context.SecurityContext;
-import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
import feign.RequestInterceptor;
import feign.RequestTemplate;
@@ -14,23 +18,19 @@ import feign.RequestTemplate;
@Configuration
public class FeignConfig implements RequestInterceptor {
- private final String AUTHORIZATION_HEADER = "Authorization";
- private final String BEARER_TOKEN_TYPE = "Bearer";
-
@Override
public void apply(RequestTemplate template) {
-// ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
-// if (null != attributes) {
-// HttpServletRequest request = attributes.getRequest();
-// String token = request.getHeader("JwtToken");
-// template.header("JwtToken", token);
-// }
- SecurityContext securityContext = SecurityContextHolder.getContext();
- Authentication authentication = securityContext.getAuthentication();
-
- if (authentication != null && authentication.getCredentials() instanceof String) {
- String token = (String) authentication.getCredentials();
- template.header(AUTHORIZATION_HEADER, String.format("%s %s", BEARER_TOKEN_TYPE, token));
+ ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
+
+ if (null != attributes) {
+ final String header = attributes.getRequest().getHeader(AUTHORIZATION_HEADER);// 提取request头信息
+
+ // 检查请求头是否包含 Bearer 前缀
+ if (StringUtils.startsWith(header, TOKEN_PREFIX)) {
+ String authToken = RegExUtils.replaceAll(header, TOKEN_PREFIX, "");// 提取 token 信息
+
+ template.header(AUTHORIZATION_HEADER, String.format("%s %s", TOKEN_PREFIX, authToken));
+ }
}
}