如何限制checkServerTrusted仅在自有服务器连接初始化时执行
问题核心原因
你当前自定义的checkServerTrusted被谷歌地图触发,本质是你的自定义TrustManager配置被全局生效,或者所有OkHttpClient实例都复用了带该配置的Builder,谷歌地图SDK内部发起网络请求时也用到了这套配置。
实现方案
方案1:隔离OkHttpClient实例(最推荐,改造成本最低)
- 不要调用
OkHttpClient.setDefault()之类的方法将自定义的OkHttpClient设为全局默认实例,你当前代码中生成的带自定义TrustManager的OkHttpClient,仅传给访问自有服务的Retrofit使用即可。 - 谷歌地图SDK内部会使用自己默认的OkHttpClient实例,不会触发你的自定义校验逻辑。
方案2:checkServerTrusted内增加域名过滤逻辑
如果确实需要全局配置自定义TrustManager,可以在校验前先判断当前请求的域名是否在自有服务器白名单内,仅匹配时才执行自定义校验,其他场景直接走系统默认校验即可:
public static OkHttpClient.Builder getCustomOkHttpClient() { try { // 自有服务器域名白名单,自行替换为实际域名 List<String> selfHostWhitelist = Arrays.asList("api.your-domain.com", "res.your-domain.com"); TrustManagerFactory tmf = TrustManagerFactory.getInstance( TrustManagerFactory.getDefaultAlgorithm()); tmf.init((KeyStore) null); TrustManager[] trustManagers = tmf.getTrustManagers(); final X509ExtendedTrustManager origTrustmanager = (X509ExtendedTrustManager) trustManagers[0]; TrustManager[] wrappedTrustManagers = new TrustManager[]{ new X509ExtendedTrustManager() { @Override public X509Certificate[] getAcceptedIssuers() { return origTrustmanager.getAcceptedIssuers(); } @Override public void checkClientTrusted(X509Certificate[] certs, String authType) throws CertificateException { origTrustmanager.checkClientTrusted(certs, authType); } @Override public void checkServerTrusted(X509Certificate[] certs, String authType) throws CertificateException { origTrustmanager.checkServerTrusted(certs, authType); } @Override public void checkServerTrusted(X509Certificate[] chain, String authType, Socket socket) throws CertificateException { if (socket instanceof SSLSocket) { SSLSession session = ((SSLSocket) socket).getSession(); String peerHost = session.getPeerHost(); // 仅白名单域名走自定义校验逻辑 if (selfHostWhitelist.contains(peerHost)) { // 此处可加入你自己的校验逻辑 origTrustmanager.checkServerTrusted(chain, authType, socket); return; } } // 非自有域名直接走系统默认校验 origTrustmanager.checkServerTrusted(chain, authType, socket); } @Override public void checkClientTrusted(X509Certificate[] chain, String authType, Socket socket) throws CertificateException { origTrustmanager.checkClientTrusted(chain, authType, socket); } @Override public void checkServerTrusted(X509Certificate[] chain, String authType, SSLEngine engine) throws CertificateException { SSLSession session = engine.getHandshakeSession(); if (session != null) { String peerHost = session.getPeerHost(); if (selfHostWhitelist.contains(peerHost)) { origTrustmanager.checkServerTrusted(chain, authType, engine); return; } } origTrustmanager.checkServerTrusted(chain, authType, engine); } @Override public void checkClientTrusted(X509Certificate[] chain, String authType, SSLEngine engine) throws CertificateException { origTrustmanager.checkClientTrusted(chain, authType, engine); } } }; // 将自定义TrustManager绑定到OkHttpClient SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, wrappedTrustManagers, new SecureRandom()); return new OkHttpClient.Builder() .sslSocketFactory(sslContext.getSocketFactory(), (X509TrustManager) wrappedTrustManagers[0]); } catch (Exception e) { throw new RuntimeException(e); } }
方案3:用CertificatePinner替代全局自定义TrustManager
如果你的需求仅为对自有服务器做证书钉住/校验,不需要自定义全局信任逻辑,可以直接使用OkHttp自带的CertificatePinner功能,仅针对自有域名配置校验规则,完全不会影响其他第三方SDK的网络请求:
val client = OkHttpClient.Builder() .certificatePinner( CertificatePinner.Builder() // 仅给自有域名配置证书公钥哈希 .add("api.your-domain.com", "sha256/替换为你自己的证书公钥哈希") .build() ) .build() val retrofit = Retrofit.Builder() .baseUrl(baseUrl) .client(client) .addConverterFactory(GsonConverterFactory.create(gson)) .build()
内容的提问来源于stack exchange,提问作者kostik
相关产品推荐
相关产品推荐

