- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在尝试为 spring cloud eureka 服务器启用 https。Yaml 配置:
server:
port: 8100
ssl:
clientAuth: want
protocol: TLS
key-store: classpath:keystore/keystore.jks
key-store-password: some
key-password: some
eureka:
instance:
prefer-ip-address: true
non-secure-port-enabled: false
secure-port-enabled: true
secure-port: ${server.port}
healthCheckUrl: https://${eureka.hostname}:${secure-port}/health
statusPageUrl: https://${eureka.hostname}:${secure-port}/info
homePageUrl: https://${eureka.hostname}:${secure-port}/
security:
basic:
enabled: true
然后我启动一个客户端来注册到服务器。我没有导入自签名证书,因此我得到了异常 sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target。我不想导入证书,因为有很多实例和证书管理成本很高。因此,我将证书放在类路径中并在启动期间加载它。我通过添加代码来覆盖客户端默认的 ssl 上下文和 ssl 套接字工厂
SSLContext.setDefault(sslContext);
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
使用feign调用其他eureka客户端时正常。然而,它在注册到 Eureka 服务器时没有任何努力。我查看了源代码,发现eureka discovery client using jersey,jersey调用了http apache client。问题是,它使用 SchemeRegistryFactory.createDefault() 最终会调用 SSLContexts.createDefault() 而不会考虑系统属性。换句话说,这个 http 客户端不会标记我的自定义 SSLContexts。所以我的问题是,是否有一种方法可以在 eureka 发现客户端中添加/重新注册/替换默认的 http 客户端?
最佳答案
翻了很多遍源码,终于找到了解决办法。我使用的是 Camden.SR5 版本,它将调用 eureka-client-1.4.12。
如果您在 DiscoveryClientOptionalArgs 中提供了一个 EurekaJerseyClient,那么 Discovery 客户端将不会初始化默认客户端。来自 DiscoveryClient 类的部分代码。
private void scheduleServerEndpointTask(EurekaTransport eurekaTransport,
DiscoveryClientOptionalArgs args) {
...
EurekaJerseyClient providedJerseyClient = args == null
? null
: args.eurekaJerseyClient;
eurekaTransport.transportClientFactory = providedJerseyClient == null
? TransportClientFactories.newTransportClientFactory(clientConfig, additionalFilters, applicationInfoManager.getInfo())
: TransportClientFactories.newTransportClientFactory(additionalFilters, providedJerseyClient);
...
}
然后我添加一个类来创建一个 DiscoveryClientOptionalArgs bean。
import com.netflix.discovery.DiscoveryClient;
import com.netflix.discovery.EurekaClientConfig;
import com.netflix.discovery.converters.wrappers.CodecWrappers;
import com.netflix.discovery.shared.transport.jersey.EurekaJerseyClient;
import com.qy.insurance.cloud.core.eureka.CustomEurekaJerseyClientBuilder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@Slf4j
public class EurekaSslConfig {
@Value("${eureka.client.service-url.defaultZone}")
private String defaultZone;
@Autowired
private EurekaClientConfig config;
@Autowired
private DefaultSslConfig defaultSslConfig;
@Bean
public DiscoveryClient.DiscoveryClientOptionalArgs discoveryClientOptionalArgs(){
if(!defaultSslConfig.isFinish()){
log.warn("Default SSLContext might not have been updated! Please check!");
}
DiscoveryClient.DiscoveryClientOptionalArgs args = new DiscoveryClient.DiscoveryClientOptionalArgs();
CustomEurekaJerseyClientBuilder clientBuilder = new CustomEurekaJerseyClientBuilder()
.withClientName("DiscoveryClient-HTTPClient-Custom")
.withUserAgent("Java-EurekaClient")
.withConnectionTimeout(config.getEurekaServerConnectTimeoutSeconds() * 1000)
.withReadTimeout(config.getEurekaServerReadTimeoutSeconds() * 1000)
.withMaxConnectionsPerHost(config.getEurekaServerTotalConnectionsPerHost())
.withMaxTotalConnections(config.getEurekaServerTotalConnections())
.withConnectionIdleTimeout(config.getEurekaConnectionIdleTimeoutSeconds() * 1000)
.withEncoderWrapper(CodecWrappers.getEncoder(config.getEncoderName()))
.withDecoderWrapper(CodecWrappers.resolveDecoder(config.getDecoderName(), config.getClientDataAccept()));
if (defaultZone.startsWith("https://")) {
clientBuilder.withSystemSSLConfiguration();
}
EurekaJerseyClient jerseyClient = clientBuilder.build();
args.setEurekaJerseyClient(jerseyClient);//Provide custom EurekaJerseyClient to override default one
return args;
}
为了确保我的自定义 EurekaJerseyClient 正常工作,我从 EurekaJerseyClientImpl 中 fork 了代码并做了一些修改。
import com.netflix.discovery.converters.wrappers.CodecWrappers;
import com.netflix.discovery.converters.wrappers.DecoderWrapper;
import com.netflix.discovery.converters.wrappers.EncoderWrapper;
import com.netflix.discovery.provider.DiscoveryJerseyProvider;
import com.netflix.discovery.shared.MonitoredConnectionManager;
import com.netflix.discovery.shared.transport.jersey.EurekaJerseyClient;
import com.netflix.discovery.shared.transport.jersey.EurekaJerseyClientImpl;
import com.netflix.discovery.shared.transport.jersey.SSLSocketFactoryAdapter;
import com.netflix.discovery.util.DiscoveryBuildInfo;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.client.apache4.config.ApacheHttpClient4Config;
import com.sun.jersey.client.apache4.config.DefaultApacheHttpClient4Config;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.impl.conn.SchemeRegistryFactory;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.util.TextUtils;
public class CustomEurekaJerseyClientBuilder {
private boolean systemSSL;
private String clientName;
private int maxConnectionsPerHost;
private int maxTotalConnections;
private String trustStoreFileName;
private String trustStorePassword;
private String userAgent;
private String proxyUserName;
private String proxyPassword;
private String proxyHost;
private String proxyPort;
private int connectionTimeout;
private int readTimeout;
private int connectionIdleTimeout;
private EncoderWrapper encoderWrapper;
private DecoderWrapper decoderWrapper;
public CustomEurekaJerseyClientBuilder withClientName(String clientName) {
this.clientName = clientName;
return this;
}
public CustomEurekaJerseyClientBuilder withUserAgent(String userAgent) {
this.userAgent = userAgent;
return this;
}
public CustomEurekaJerseyClientBuilder withConnectionTimeout(int connectionTimeout) {
this.connectionTimeout = connectionTimeout;
return this;
}
public CustomEurekaJerseyClientBuilder withReadTimeout(int readTimeout) {
this.readTimeout = readTimeout;
return this;
}
public CustomEurekaJerseyClientBuilder withConnectionIdleTimeout(int connectionIdleTimeout) {
this.connectionIdleTimeout = connectionIdleTimeout;
return this;
}
public CustomEurekaJerseyClientBuilder withMaxConnectionsPerHost(int maxConnectionsPerHost) {
this.maxConnectionsPerHost = maxConnectionsPerHost;
return this;
}
public CustomEurekaJerseyClientBuilder withMaxTotalConnections(int maxTotalConnections) {
this.maxTotalConnections = maxTotalConnections;
return this;
}
public CustomEurekaJerseyClientBuilder withProxy(String proxyHost, String proxyPort, String user, String password) {
this.proxyHost = proxyHost;
this.proxyPort = proxyPort;
this.proxyUserName = user;
this.proxyPassword = password;
return this;
}
public CustomEurekaJerseyClientBuilder withSystemSSLConfiguration() {
this.systemSSL = true;
return this;
}
public CustomEurekaJerseyClientBuilder withTrustStoreFile(String trustStoreFileName, String trustStorePassword) {
this.trustStoreFileName = trustStoreFileName;
this.trustStorePassword = trustStorePassword;
return this;
}
public CustomEurekaJerseyClientBuilder withEncoder(String encoderName) {
return this.withEncoderWrapper(CodecWrappers.getEncoder(encoderName));
}
public CustomEurekaJerseyClientBuilder withEncoderWrapper(EncoderWrapper encoderWrapper) {
this.encoderWrapper = encoderWrapper;
return this;
}
public CustomEurekaJerseyClientBuilder withDecoder(String decoderName, String clientDataAccept) {
return this.withDecoderWrapper(CodecWrappers.resolveDecoder(decoderName, clientDataAccept));
}
public CustomEurekaJerseyClientBuilder withDecoderWrapper(DecoderWrapper decoderWrapper) {
this.decoderWrapper = decoderWrapper;
return this;
}
public EurekaJerseyClient build() {
MyDefaultApacheHttpClient4Config config = new MyDefaultApacheHttpClient4Config();
try {
return new EurekaJerseyClientImpl(connectionTimeout, readTimeout, connectionIdleTimeout, config);
} catch (Throwable e) {
throw new RuntimeException("Cannot create Jersey client ", e);
}
}
class MyDefaultApacheHttpClient4Config extends DefaultApacheHttpClient4Config {
private static final String PROTOCOL = "https";
private static final String PROTOCOL_SCHEME = "SSL";
private static final int HTTPS_PORT = 443;
private static final String KEYSTORE_TYPE = "JKS";
MyDefaultApacheHttpClient4Config() {
MonitoredConnectionManager cm;
if (systemSSL) {
cm = createSystemSslCM();
} else {
cm = createDefaultSslCM();
}
if (proxyHost != null) {
addProxyConfiguration(cm);
}
DiscoveryJerseyProvider discoveryJerseyProvider = new DiscoveryJerseyProvider(encoderWrapper, decoderWrapper);
getSingletons().add(discoveryJerseyProvider);
// Common properties to all clients
cm.setDefaultMaxPerRoute(maxConnectionsPerHost);
cm.setMaxTotal(maxTotalConnections);
getProperties().put(ApacheHttpClient4Config.PROPERTY_CONNECTION_MANAGER, cm);
String fullUserAgentName = (userAgent == null ? clientName : userAgent) + "/v" + DiscoveryBuildInfo.buildVersion();
getProperties().put(CoreProtocolPNames.USER_AGENT, fullUserAgentName);
// To pin a client to specific server in case redirect happens, we handle redirects directly
// (see DiscoveryClient.makeRemoteCall methods).
getProperties().put(ClientConfig.PROPERTY_FOLLOW_REDIRECTS, Boolean.FALSE);
getProperties().put(ClientPNames.HANDLE_REDIRECTS, Boolean.FALSE);
}
private void addProxyConfiguration(MonitoredConnectionManager cm) {
if (proxyUserName != null && proxyPassword != null) {
getProperties().put(ApacheHttpClient4Config.PROPERTY_PROXY_USERNAME, proxyUserName);
getProperties().put(ApacheHttpClient4Config.PROPERTY_PROXY_PASSWORD, proxyPassword);
} else {
// Due to bug in apache client, user name/password must always be set.
// Otherwise proxy configuration is ignored.
getProperties().put(ApacheHttpClient4Config.PROPERTY_PROXY_USERNAME, "guest");
getProperties().put(ApacheHttpClient4Config.PROPERTY_PROXY_PASSWORD, "guest");
}
getProperties().put(DefaultApacheHttpClient4Config.PROPERTY_PROXY_URI, "http://" + proxyHost + ":" + proxyPort);
}
private MonitoredConnectionManager createSystemSslCM() {
MonitoredConnectionManager cm;
X509HostnameVerifier hostnameVerifier = SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;
SSLConnectionSocketFactory systemSocketFactory = new SSLConnectionSocketFactory(
(javax.net.ssl.SSLSocketFactory) javax.net.ssl.SSLSocketFactory.getDefault(),
split(System.getProperty("https.protocols")),
split(System.getProperty("https.cipherSuites")),
hostnameVerifier);
SSLSocketFactory sslSocketFactory = new SSLSocketFactoryAdapter(systemSocketFactory);
SchemeRegistry sslSchemeRegistry = new SchemeRegistry();
sslSchemeRegistry.register(new Scheme(PROTOCOL, HTTPS_PORT, sslSocketFactory));
cm = new MonitoredConnectionManager(clientName, sslSchemeRegistry);
return cm;
}
/**
* @see SchemeRegistryFactory#createDefault()
*/
private MonitoredConnectionManager createDefaultSslCM() {
final SchemeRegistry registry = new SchemeRegistry();
registry.register(
new Scheme("http", 80, PlainSocketFactory.getSocketFactory()));
registry.register(
new Scheme("https", 443, new SSLSocketFactoryAdapter(SSLConnectionSocketFactory.getSocketFactory())));
return new MonitoredConnectionManager(clientName, registry);
}
private String[] split(final String s) {
if (TextUtils.isBlank(s)) {
return null;
}
return s.split(" *, *");
}
}
}
希望这可以帮助那些像我一样不容易在 Production JVM 中导入证书的人。
关于java - 如何覆盖 Spring Cloud Eureka 默认发现客户端默认 ssl 上下文?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42289196/
我有三台计算机,并且开发了Eureka feign和eureka客户服务应用程序,并将它们发布在docker中。上面的配置: 1.我在不同的Docker容器中发布了Eureka和feign,但它们位于
我正在通过阅读 this article 学习 Spring Cloud Netflix ,但是我开始对本文中的不同术语感到困惑,它们是: Eureka 服务。 据我了解,它是在唯一 uri 上运行的
Eureka 服务器设置 pom.xml 1.8 Hoxton.SR1 org.springframework.cloud spring
我正在实现服务发现并评估两个选项:Eureka 和 Consul。 帮我决定!我倾向于 Eureka,但我需要解决一个主要的技术问题。我的基础架构基于 openshift。我可以让多个容器在负载均衡器
他们是在 Eureka 中忽略区域或定义可接受区域列表的方法,例如,如果我们有 3 个区域(office、shahbour、joe ) 我希望区域 shahbour 中的服务仅使用 shahbour
我想在没有 Spring Boot 的情况下进行服务发现。 所以我下载了netflix项目example并且因为它的 gradle 项目我想使它成为 maven。 所以我创建了 maven 项目,导入
我想知道它是否存在让 Eureka 客户端知道它实际 instanceId 的方法(我正在寻找一种既适用于同一主机又适用于分布式 conf 的解决方案)。 到目前为止,我使用的是手动定义的 eurek
我对Docker和微服务有疑问。因此,我创建了ZuulService,EurekaServer + EurekaService,它在没有docker的情况下也可以正常工作。 但是我正在尝试研究dock
我正在研究用于服务发现的 Eureka,我发现如果我终止一个进程,Eureka 会将其显示为“DOWN”。有一天它会自己清理并移除它吗? 场景是这样的:假设我正在使用亚马逊 AWS。我想通过这种方式上
我正在创建一系列 ImageCheckRows 作为 SelectableSection,我想设置一些默认值。基本上每一行都返回一个真/假值,所以在某处应该有一个简单的方法来设置每一行的真或假。我尝试
如何创建一个表单,其中文本窗口可以在左侧添加一个按钮,类似于末尾附加的照片?这个想法是,通过输入textRow并单击按钮来显示我在数据库中搜索的信息,然后显示Eureka表单,按下搜索按钮后可以生成E
我有一台 Eureka 服务器。 server: port: 8761 eureka: client: registerWithEureka: false fetchRegis
我在 Spring Boot 应用程序中设置了 Eureka,并且 Eureka 内置了一个我喜欢的整洁的 Web UI 这是我在 application.yml 中的配置 server: por
我有一个 Eureka 服务器在端口 8761 (localhost:8761/eureka) 上运行,并且我有一个 Zuul 应用程序,我想向 eureka 注册,但我不断收到相同的错误: Can'
我一直在互联网上寻找有关将 spring-cloud-netflix eureka 服务器部署到 aws 的正确方法的指导。我们已经在使用 spring-cloud 和 nodejs 的微服务中使用了
我已经创建了 Eureka 服务注册表并将服务注册到其中。目前只有一个服务实例正在运行。如何添加同一服务的多个实例?我正在开发独立的应用程序。我正在通过 Rest 模板访问服务。我正在关注 https
我能够让 Eureka 服务器以对等模式运行。但我很好奇的一件事是如何让服务发现客户端注册到多个 eureka 服务器。 我的用例是这样的: 假设我有一个服务注册到其中一台 eureka 服务器(例如
在 Cloud config 中,我们存储了其他微服务可以访问的配置。在 Eureka 中,我们也存储配置信息。那么有什么区别以及何时使用什么? 最佳答案 了解更多之后,我明白 Eureka 不是用来
我有一个 Spring Boot 应用程序,它也是一个 Eureka 客户端。应用程序的正常行为是在 UP 启动时向 Eureka 服务器 注册。我有一个要求,即在部署期间完成冒烟测试之前,应用程序不
我是微服务新手(使用 Spring Boot)。复制生产代码并尝试在我的本地运行。我应该怎么做才能成功运行代码?有配置服务器、eureka 服务器、tomcat 服务器、zuul 路由工具、ribbo
我是一名优秀的程序员,十分优秀!