安全规范中有一条是要求尽量使用https而弃用http(新Chrome将标记非HTTPS网站为不安全),其实启用https和之前的ipv6改造一样,并不是什么高难度或者工作流繁多的的改造,只需将中间件启用https支持即可。在spring boot项目中,基本上都是使用内置的中间件(tomcat、netty等),下面记录下改造的思路:

方案1: 服务均启用https,步骤有:

  1. 所有的micro service均启用https
  2. 把eureka的注册地址改为https方式
  3. 把config service的注册地址改为https方式
  4. 把feign的调用方式改为支持https方式
  5. 每个micro service均需导入证书,并且访问的时候需要导入证书(不然会报unable to find valid certification path to requested target错误)
  6. 证书里需要把micro service的serviceId注册进去(不然会报Certificate doesn't match any of the subject alternative names错误)

方案比较稳妥,所有服务中均走了ssl,满足安全条件,就是乍一看改造量有点多啊......

方案2:micro service只会暴露gateway,其余服务均是不暴露的,因此我们可以只改造gateway服务,步骤有:

  1. gateway service启用https
  2. gateway service改造lb://micro_service_id的地址替换方式

该方案改造量最小,且由于spring cloud的服务隔离的关系,并无需担心其余服务的安全问题。


实现方案:

  1. 生成证书

  可以用JDK自带的keytool工具,来生成证书,具体语法为:

C:\Users\Administrator>keytool
密钥和证书管理工具 命令: -certreq 生成证书请求
-changealias 更改条目的别名
-delete 删除条目
-exportcert 导出证书
-genkeypair 生成密钥对
-genseckey 生成密钥
-gencert 根据证书请求生成证书
-importcert 导入证书或证书链
-importpass 导入口令
-importkeystore 从其他密钥库导入一个或所有条目
-keypasswd 更改条目的密钥口令
-list 列出密钥库中的条目
-printcert 打印证书内容
-printcertreq 打印证书请求的内容
-printcrl 打印 CRL 文件的内容
-storepasswd 更改密钥库的存储口令 使用 "keytool -command_name -help" 获取 command_name 的用法

  生成证书的语句为:

keytool -genkeypair -alias "ncdt" -keyalg "RSA" -keystore "C:\ncdt.keystore"

  执行后,根据提示完成即可(测试用的话,直接一直按回车,最后确认y即可),如下图:

  2. spring cloud gateway项目启用https(其实也就是spring boot项目启用https),只需要在application.yml里增加ssl配置即可。

server:
port: 443
ssl:
key-alias: ncdt
enabled: true
key-store-password: password
key-store-type: JKS
key-store: ncdt.keystore

  3.spring cloud gateway项目增加HttpsReconstructFilter

  如何来重写这个filter呢,首先先不要写这个filter,直接启动gateway并访问地址:https://localhost/,就会报如下错误(里面的*****是我自己的服务名,故隐藏了):

2018-09-19 11:19:26.420  INFO 10808 --- [ctor-http-nio-1] c.netflix.loadbalancer.BaseLoadBalancer  : Client: ***** instantiated a LoadBalancer: DynamicServerListLoadBalancer:{NFLoadBalancer:name=*****,current list of Servers=[],Load balancer stats=Zone stats: {},Server stats: []}ServerList:null
2018-09-19 11:19:26.424 INFO 10808 --- [ctor-http-nio-1] c.n.l.DynamicServerListLoadBalancer : Using serverListUpdater PollingServerListUpdater
2018-09-19 11:19:26.427 INFO 10808 --- [ctor-http-nio-1] c.n.l.DynamicServerListLoadBalancer : DynamicServerListLoadBalancer for client ***** initialized: DynamicServerListLoadBalancer:{NFLoadBalancer:name=*****,current list of Servers=[],Load balancer stats=Zone stats: {},Server stats: []}ServerList:org.springframework.cloud.netflix.ribbon.eureka.DomainExtractingServerList@7b98208b
2018-09-19 11:19:26.490 ERROR 10808 --- [ctor-http-nio-1] .a.w.r.e.DefaultErrorWebExceptionHandler : Failed to handle request [GET https://localhost/******] org.springframework.cloud.gateway.support.NotFoundException: Unable to find instance for *****
at org.springframework.cloud.gateway.filter.LoadBalancerClientFilter.filter(LoadBalancerClientFilter.java:72) ~[spring-cloud-gateway-core-2.0.1.RELEASE.jar:2.0.1.RELEASE]
at org.springframework.cloud.gateway.handler.FilteringWebHandler$GatewayFilterAdapter.filter(FilteringWebHandler.java:133) ~[spring-cloud-gateway-core-2.0.1.RELEASE.jar:2.0.1.RELEASE]
at org.springframework.cloud.gateway.filter.OrderedGatewayFilter.filter(OrderedGatewayFilter.java:44) ~[spring-cloud-gateway-core-2.0.1.RELEASE.jar:2.0.1.RELEASE]
at org.springframework.cloud.gateway.handler.FilteringWebHandler$DefaultGatewayFilterChain.lambda$filter$0(FilteringWebHandler.java:115) ~[spring-cloud-gateway-core-2.0.1.RELEASE.jar:2.0.1.RELEASE]
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:45) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoPeekTerminal.subscribe(MonoPeekTerminal.java:61) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.Mono.subscribe(Mono.java:3080) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.drain(MonoIgnoreThen.java:172) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoIgnoreThen.subscribe(MonoIgnoreThen.java:56) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.Mono.subscribe(Mono.java:3080) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.drain(MonoIgnoreThen.java:172) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoIgnoreThen.subscribe(MonoIgnoreThen.java:56) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:150) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onNext(FluxSwitchIfEmpty.java:67) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoNext$NextSubscriber.onNext(MonoNext.java:76) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.innerNext(FluxConcatMap.java:271) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.FluxConcatMap$ConcatMapInner.onNext(FluxConcatMap.java:803) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:108) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onNext(FluxSwitchIfEmpty.java:67) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1083) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:144) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:108) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoNext$NextSubscriber.onNext(MonoNext.java:76) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.innerNext(FluxConcatMap.java:271) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.FluxConcatMap$ConcatMapInner.onNext(FluxConcatMap.java:803) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:73) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.FluxPeek$PeekSubscriber.onNext(FluxPeek.java:185) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1083) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoFilterWhen$MonoFilterWhenMain.onNext(MonoFilterWhen.java:138) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:1640) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoFilterWhen$MonoFilterWhenMain.onSubscribe(MonoFilterWhen.java:103) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoJust.subscribe(MonoJust.java:54) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoFilterWhen.subscribe(MonoFilterWhen.java:56) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoPeek.subscribe(MonoPeek.java:71) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoOnErrorResume.subscribe(MonoOnErrorResume.java:44) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.Mono.subscribe(Mono.java:3080) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.drain(FluxConcatMap.java:418) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.onNext(FluxConcatMap.java:241) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.FluxDematerialize$DematerializeSubscriber.onNext(FluxDematerialize.java:114) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.FluxDematerialize$DematerializeSubscriber.onNext(FluxDematerialize.java:42) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.FluxIterable$IterableSubscription.slowPath(FluxIterable.java:244) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.FluxIterable$IterableSubscription.request(FluxIterable.java:202) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.FluxDematerialize$DematerializeSubscriber.request(FluxDematerialize.java:157) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.onSubscribe(FluxConcatMap.java:227) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.FluxDematerialize$DematerializeSubscriber.onSubscribe(FluxDematerialize.java:88) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:140) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:64) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.FluxDematerialize.subscribe(FluxDematerialize.java:39) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.FluxDefer.subscribe(FluxDefer.java:55) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.FluxConcatMap.subscribe(FluxConcatMap.java:121) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoNext.subscribe(MonoNext.java:40) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoMap.subscribe(MonoMap.java:55) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoFlatMap.subscribe(MonoFlatMap.java:60) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoSwitchIfEmpty.subscribe(MonoSwitchIfEmpty.java:44) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoMap.subscribe(MonoMap.java:55) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.Mono.subscribe(Mono.java:3080) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.drain(FluxConcatMap.java:418) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.onSubscribe(FluxConcatMap.java:210) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:140) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:64) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.FluxConcatMap.subscribe(FluxConcatMap.java:121) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoNext.subscribe(MonoNext.java:40) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoSwitchIfEmpty.subscribe(MonoSwitchIfEmpty.java:44) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoFlatMap.subscribe(MonoFlatMap.java:60) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoFlatMap.subscribe(MonoFlatMap.java:60) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoPeekTerminal.subscribe(MonoPeekTerminal.java:61) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:150) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1083) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoZip$ZipCoordinator.signal(MonoZip.java:247) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoZip$ZipInner.onNext(MonoZip.java:329) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:1640) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoZip$ZipInner.onSubscribe(MonoZip.java:318) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoJust.subscribe(MonoJust.java:54) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.Mono.subscribe(Mono.java:3080) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoZip.subscribe(MonoZip.java:128) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoFlatMap.subscribe(MonoFlatMap.java:60) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoPeekTerminal.subscribe(MonoPeekTerminal.java:61) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoPeekFuseable.subscribe(MonoPeekFuseable.java:74) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoOnErrorResume.subscribe(MonoOnErrorResume.java:44) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoOnErrorResume.subscribe(MonoOnErrorResume.java:44) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoOnErrorResume.subscribe(MonoOnErrorResume.java:44) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.Mono.subscribe(Mono.java:3080) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.drain(MonoIgnoreThen.java:172) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoIgnoreThen.subscribe(MonoIgnoreThen.java:56) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoPeekFuseable.subscribe(MonoPeekFuseable.java:70) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.core.publisher.MonoPeekTerminal.subscribe(MonoPeekTerminal.java:61) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
at reactor.ipc.netty.channel.ChannelOperations.applyHandler(ChannelOperations.java:380) ~[reactor-netty-0.7.8.RELEASE.jar:0.7.8.RELEASE]
at reactor.ipc.netty.http.server.HttpServerOperations.onHandlerStart(HttpServerOperations.java:398) ~[reactor-netty-0.7.8.RELEASE.jar:0.7.8.RELEASE]
at io.netty.util.concurrent.AbstractEventExecutor.safeExecute$$$capture(AbstractEventExecutor.java:163) ~[netty-common-4.1.27.Final.jar:4.1.27.Final]
at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java) ~[netty-common-4.1.27.Final.jar:4.1.27.Final]
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:404) ~[netty-common-4.1.27.Final.jar:4.1.27.Final]
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:464) ~[netty-transport-4.1.27.Final.jar:4.1.27.Final]
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:884) ~[netty-common-4.1.27.Final.jar:4.1.27.Final]
at java.lang.Thread.run(Thread.java:745) ~[na:1.8.0_77]

  可以看到里面调用的是ribbon的loadbalancer,因此我们可以直接看gateway里的全局过滤器接口GlobalFilter,找这个接口的所有实现类:

  找到LoadBalancerClientFilter,可以看到这个filter调用了loadBalancer.reconstructURI(new DelegatingServiceInstance(instance, overrideScheme), uri),并重新写入到GATEWAY_REQUEST_URL_ATTR中。

  在继续往下找(代码不难),最终会看到这个filter是执行了RibbonUtils的一个私有方法upgradeConnection,功能是:如果调用的服务要求安全的,就判断原始uri的scheme是否是http,是则转化为https,否则就按照原始请求的。

  那么我们的要求是gateway为https,转发后的uri依然保持http不变,与上功能相反,因此我们可以仿造LoadBalancerClientFilter,并重写RibbonUtilsupgradeConnection方法,调整filter的执行顺序,由于不是升级连接,因此重命名了一下,代码如下:

/**
* @author zhangqiuyang
* Created on 2018/6/9.
*/
@Configuration
public class HttpsReconstructFilter implements GlobalFilter, Ordered {
private static final int HTTPS_RECONSTRUCT_FILTER_ORDER = 10101;

    /**
* Process the Web request and (optionally) delegate to the next
* {@code WebFilter} through the given {@link GatewayFilterChain}.
*
* @param exchange the current server exchange
* @param chain provides a way to delegate to the next filter
* @return {@code Mono<Void>} to indicate when request processing is complete
*/
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
URI url = exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR);
if (url != null && "https".equals(url.getScheme())) {
exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, reconstructURIConnection(url));
}
return chain.filter(exchange);
} /**
* 重构url,把https修改为http
*
* @param uri
* @return
*/
private static URI reconstructURIConnection(URI uri) {
UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUri(uri).scheme("http");
if (uri.getRawQuery() != null) {
// When building the URI, UriComponentsBuilder verify the allowed characters and does not
// support the '+' so we replace it for its equivalent '%20'.
// See issue https://jira.spring.io/browse/SPR-10172
uriComponentsBuilder.replaceQuery(uri.getRawQuery().replace("+", "%20"));
}
return uriComponentsBuilder.build(true).toUri();
} /**
* Get the order value of this object.
* <p>Higher values are interpreted as lower priority. As a consequence,
* the object with the lowest value has the highest priority (somewhat
* analogous to Servlet {@code load-on-startup} values).
* <p>Same order values will result in arbitrary sort positions for the
* affected objects.
*
* @return the order value
* @see #HIGHEST_PRECEDENCE
* @see #LOWEST_PRECEDENCE
*/
@Override
public int getOrder() {
return HTTPS_RECONSTRUCT_FILTER_ORDER;
}
}

改造就完成了,重启服务后访问,就可以看到效果。

生产环境证书:

  许多生产环境的证书都是从godaddy(参考官方帮助)或者其他网站上申请的,得到的是一个gd_bundle开头的.crt证书和一个随机名称.crt证书,那这时如果要在spring boot上用这个证书,则需要进行一下转换,把证书转换成jks证书

openssl pkcs12 -export -in 随机名称证书.crt -inkey 私钥.key -out ncdt.p12 -name tomcat -CAfile gd_bundle开头证书.crt -caname root -chain

  执行完会要求输入密码,自己指定即可。

keytool -importkeystore -destkeystore ncdt.jks -srckeystore ncdt.p12 -srcstoretype PKCS12

  执行完再次输入密码,生成.jks文件。

同时,spring boot的ssl配置应该为:

server:
port: 443
ssl:
enabled: true
key-store-password: 密码
key-store: ncdt.jks

重启完成配置。

(四)启用HTTPS的更多相关文章

  1. 【转】Tomcat启用HTTPS协议配置过程

    转载请注明出处: http://blog.csdn.net/gane_cheng/article/details/53001846 http://www.ganecheng.tech/blog/530 ...

  2. 架设证书服务器 及 让IIS启用HTTPS服务(转)

    无废话图文教程,教你一步一步搭建CA服务器,以及让IIS启用HTTPS服务. 一.架设证书服务器(CA服务) 1.在系统控制面板中,找到“添加/删除程序”,点击左侧的“添加/删除windows组件”, ...

  3. 我是如何将网站全站启用Https的?-记录博客安装配置SSL证书全过程

    评论»   文章目录 为什么要Https 如何选择Https 安装部署SSL证书 平滑过渡Https 搜索引擎的响应 启用Https小结 正如大家所看到的,部落全站已经启用了Https访问了,连续几天 ...

  4. Tomcat启用HTTPS协议配置过程

    Article1较为简洁,Article2较为详细,测试可行. Article1 概念简介 Tomcat 服务器是一个免费的开放源代码的Web 应用服务器,属于轻量级应用服务器,在中小型系统和并发访问 ...

  5. EasyDSS高性能RTMP、HLS(m3u8)、HTTP-FLV、RTSP流媒体服务器启用https服务申请免费证书

    背景分析 目前想在 web 上使用 HTTPS 的话, 你需要获得一个证书文件, 该证书由一个受浏览器信任的公司所签署. 一旦你获得了它, 你就在你的 web 服务器上指定其所在的位置, 以及与你关联 ...

  6. WordPress安全篇(1):WordPress网站启用HTTPS详细教程

    以前我们浏览网页使用的都是HTTP协议,HTTP使用明文传输,所以传输过程中很容易遭受黑客窃取.篡改数据,很不安全.在WordPress网站上启用HTTPS协议访问后,能大大提升站点的安全性,启用HT ...

  7. 关于启用 HTTPS 的一些经验分享(二)

    转载: 关于启用 HTTPS 的一些经验分享(二) 几天前,一位朋友问我:都说推荐用 Qualys SSL Labs 这个工具测试 SSL 安全性,为什么有些安全实力很强的大厂家评分也很低?我认为这个 ...

  8. 关于启用 HTTPS 的一些经验分享(一)

    转载: 关于启用 HTTPS 的一些经验分享(一) 随着国内网络环境的持续恶化,各种篡改和劫持层出不穷,越来越多的网站选择了全站 HTTPS.就在今天,免费提供证书服务的 Let's Encrypt ...

  9. 启用https协议的方法

    提醒:启用https协议会降低服务器性能,如非必要不必启用 一.用openssl生成密钥.证书: 1.生成RSA密钥的方法 openssl genrsa -out privkey.pem 2048 建 ...

随机推荐

  1. Python单元测试框架unittest使用方法讲解

    这篇文章主要介绍了Python单元测试框架unittest使用方法讲解,本文讲解了unittest概述.命令行接口.测试案例自动搜索.创建测试代码.构建测试套件方法等内容,需要的朋友可以参考下   概 ...

  2. day01-struts框架

    一.框架概述 1.框架的意义与作用: 所谓框架,就是把一些繁琐的重复性代码封装起来,使程序员在编码中把更多的经历放到业务需求的分析和理解上面. 特点:封装了很多细节,程序员在使用的时候会非常简单. 2 ...

  3. 在 Windows Vista、Windows 7 和 Windows Server 2008 上设置 SharePoint 2010 开发环境

    适用范围: SharePoint Foundation 2010 | SharePoint Server 2010 本文内容 步骤 1:选择和预配置操作系统 步骤 2:安装 SharePoint 20 ...

  4. SVN的使用教程(一)

    SVN使用 第一章 配置SVN 请根据下方网址配置SVN: https://blog.csdn.net/daobantutu/article/details/60467185 安装VisualSVN ...

  5. JavaScript递归深度问题

    递归是有限的东西: function fact(num) { if (num <= 1) { return 1; } else { return fact(num - 1); } } 测试结果是 ...

  6. pb getchild获取DropDownDW子窗体后进行取值

    datawindowchild ldwc if dw_1.getchild("dwmc", ldwc) = 1 then  long ll_f  ll_f = ldwc.find( ...

  7. Selenium2学习(十八)-- js处理内嵌div滚动条

    前言 前面有篇专门用js解决了浏览器滚动条的问题,生活总是多姿多彩,有的滚动条就在页面上,这时候又得仰仗js大哥来解决啦. 一.内嵌滚动条 1.下面这张图就是内嵌div带有滚动条的样子,记住它的长相. ...

  8. Qt 静态编译发布和动态编译发布

    静态编译发布 你写了一个小型Qt程序,发布的时候不想要一大堆dll文件,就只想打包成一个exe文件,那么就需要用到静态编译. 下面的教程就是Qt静态编译环境配置 Qt5.6静态编译包下载地址 1.下载 ...

  9. js数据封装处理

    var arr = [ { id: "1", date: "2018-07-27", time: "10:00-12:00", schedu ...

  10. 多目标规划——fgoalattain

    多目标规划 多个目标函数,之间可以用他们的重要程度分析,来一次进行这个序贯算法,当然也可以无限逼近的方案——​ clc,clear; % 约束 a = [- - - - ]; b = [- - ]; ...