You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ktor集成OkHttp如何使用key和pem证书发起mTLS POST请求

Ktor(OkHttp引擎)双向TLS配置实现

以下实现完全对齐给出的curl命令行为,不需要额外配置服务端信任证书,直接加载本地私钥和PEM证书即可完成mTLS握手:

前置依赖

先在build.gradle.kts中引入必要依赖:

dependencies {
    implementation("io.ktor:ktor-client-core:2.3.7")
    implementation("io.ktor:ktor-client-okhttp:2.3.7")
    // 按需引入序列化、日志等其他组件
}

如果你的私钥是-----BEGIN RSA PRIVATE KEY-----开头的PKCS#1格式,额外加BouncyCastle依赖用于解析:

implementation("org.bouncycastle:bcpkix-jdk15on:1.77")

也可以直接用openssl命令把私钥转成通用PKCS#8格式,避免额外依赖:

openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in mykey.key -out mykey_pkcs8.key

完整实现代码

import io.ktor.client.*
import io.ktor.client.engine.okhttp.*
import io.ktor.client.request.*
import io.ktor.client.statement.*
import io.ktor.http.*
import org.bouncycastle.openssl.PEMKeyPair
import org.bouncycastle.openssl.PEMParser
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter
import java.io.File
import java.io.FileReader
import java.security.KeyFactory
import java.security.KeyStore
import java.security.cert.CertificateFactory
import java.security.cert.X509Certificate
import java.security.spec.PKCS8EncodedKeySpec
import javax.net.ssl.KeyManagerFactory
import javax.net.ssl.SSLContext
import javax.net.ssl.TrustManagerFactory
import javax.net.ssl.X509TrustManager

fun buildMtlsClient(): HttpClient {
    // 加载PEM格式客户端证书
    val certFactory = CertificateFactory.getInstance("X.509")
    val clientCert = certFactory.generateCertificate(File("mycert.pem").inputStream()) as X509Certificate

    // 加载私钥
    val privateKey = if (File("mykey.key").readText().startsWith("-----BEGIN PRIVATE KEY-----")) {
        // 解析PKCS#8格式私钥
        val keyContent = File("mykey.key").readText()
            .replace("-----BEGIN PRIVATE KEY-----", "")
            .replace("-----END PRIVATE KEY-----", "")
            .replace("\\s".toRegex(), "")
        val keyBytes = java.util.Base64.getDecoder().decode(keyContent)
        KeyFactory.getInstance("RSA").generatePrivate(PKCS8EncodedKeySpec(keyBytes))
    } else {
        // 解析PKCS#1格式私钥
        val pemParser = PEMParser(FileReader("mykey.key"))
        val keyPair = pemParser.readObject() as PEMKeyPair
        JcaPEMKeyConverter().getKeyPair(keyPair).private
    }

    // 构造存储客户端身份凭证的KeyStore
    val clientKeyStore = KeyStore.getInstance(KeyStore.getDefaultType()).apply {
        load(null, null)
        setKeyEntry(
            "mtls-key",
            privateKey,
            // 私钥设置了密码就替换成对应字符数组,无密码传空数组
            CharArray(0),
            arrayOf(clientCert)
        )
    }

    // 初始化客户端凭证管理器
    val keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()).apply {
        init(clientKeyStore, CharArray(0))
    }

    // 复用系统默认信任库,和curl默认行为一致,无需额外导入服务端证书
    val trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()).apply {
        init(null as KeyStore?)
    }
    val defaultTrustManager = trustManagerFactory.trustManagers.first() as X509TrustManager

    // 构造TLS上下文
    val sslContext = SSLContext.getInstance("TLS").apply {
        init(keyManagerFactory.keyManagers, trustManagerFactory.trustManagers, null)
    }

    // 初始化OkHttp引擎的Ktor客户端
    return HttpClient(OkHttp) {
        engine {
            config {
                sslSocketFactory(sslContext.socketFactory, defaultTrustManager)
            }
        }
    }
}

// POST请求调用示例
suspend fun callTargetEndpoint() {
    val mtlsClient = buildMtlsClient()
    val resp = mtlsClient.post("https://someurl.com/my-endpoint") {
        contentType(ContentType.Application.Json)
        // 替换成实际的请求体内容
        setBody("""{"testParam":"testValue"}""")
    }
    // 处理响应
    println(resp.bodyAsText())
    mtlsClient.close()
}

注意事项

  • 私钥文件路径、证书文件路径请替换成你项目中的实际存储路径,生产环境建议把凭证放到资源目录读取,不要硬编码磁盘路径。
  • 如果私钥设置了访问密码,把代码里的CharArray(0)替换成实际密码对应的字符数组即可。
  • 不要使用“信任所有证书”的自定义TrustManager实现,会跳过服务端证书校验带来中间人攻击风险,上述配置已经和curl的默认校验逻辑完全对齐。

内容的提问来源于stack exchange,提问作者Coyado

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 07:36:32