如何在KMM KTOR中信任自我签名的证书?
我有一台具有自签名证书的服务器,没有域名(仅静态IP地址),该服务器仅为Android和iOS客户端提供API,因此IP和自签名证书足以满足我的目的。
移动客户端是在KMM上写的,它使用KTOR客户端执行请求:
apigateway.kt:
class ApiGateway(
private val rootUrl: String,
private val clientId: String,
private val secretKey: String,
private val accountManager: IAccountManagerGateway,
private val getDeviceName: GetDeviceNameUseCase,
) : IApiGateway {
private val client = HttpClient {
installContentNegotiation()
installLogging()
configureRequest()
configureResponseValidator()
installAuth()
}
private var account: Account? = this.accountManager.getAccount()
private fun HttpClientConfig<*>.configureRequest() {
defaultRequest {
url([email protected])
accept(ContentType.Application.Json)
contentType(ContentType.Application.Json)
}
}
private fun HttpClientConfig<*>.configureResponseValidator() {
HttpResponseValidator {
validateResponse { // Stub
when (it.status.value) {
in 300..399 -> throw ClientException(it.bodyAsText())
in 400..499 -> throw ClientException(it.bodyAsText())
in 500..599 -> throw ClientException(it.bodyAsText())
}
}
}
}
private fun HttpClientConfig<*>.installAuth() {
install(Auth) {
bearer {
sendWithoutRequest { request ->
val url = request.url.build().toString()
!(
url.contains("/api/oauth2/token")
|| (url.contains("/api/users") &&
request.method == HttpMethod.Post
)
)
}
loadTokens {
[email protected]?.let {
BearerTokens(accessToken = it.accessToken, refreshToken = it.refreshToken)
}
}
refreshTokens {
[email protected]?.let {
[email protected]()
BearerTokens(accessToken = it.accessToken, refreshToken = it.refreshToken)
}
}
}
}
}
private fun HttpClientConfig<*>.installContentNegotiation() {
install(ContentNegotiation) {
json()
}
}
private fun HttpClientConfig<*>.installLogging() {
install(Logging) {
logger = Logger.SIMPLE
level = LogLevel.ALL
}
}
override suspend fun getMe(): Profile {
return this.client.get("/api/users/me").body()
}
// And so on
}
不幸的是,httpclient
crastes crastes https
发送请求。到具有自签名证书的服务器:
iOS上的Android上:
I/System.out: HttpClient: REQUEST https://xxx.xxx.xxx.xxx:xxx/api/oauth2/token failed with exception: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
:
Uncaught Kotlin exception: io.ktor.client.engine.darwin.DarwinHttpRequestException: Exception in http request: Error Domain=NSURLErrorDomain Code=-1202 "The certificate for this server is invalid. You might be connecting to a server that is pretending to be “xxx.xxx.xxx.xxx” which could put your confidential information at risk." UserInfo={NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, _kCFStreamErrorDomainKey=3, NSErrorPeerCertificateChainKey=(
"<cert(0x15704bc00) s: xxx.xxx.xxx.xxx i: xxx.xxx.xxx.xxx>"
我如何设置KTOR客户端以信任自签名证书?
I have a server with self-signed certificate and without domain name (just static IP address), this server provides API for Android and iOS clients only, so IP and self-signed certificate is enough for my purposes.
The mobile client is written on KMM and it uses Ktor client to perform requests:
ApiGateway.kt:
class ApiGateway(
private val rootUrl: String,
private val clientId: String,
private val secretKey: String,
private val accountManager: IAccountManagerGateway,
private val getDeviceName: GetDeviceNameUseCase,
) : IApiGateway {
private val client = HttpClient {
installContentNegotiation()
installLogging()
configureRequest()
configureResponseValidator()
installAuth()
}
private var account: Account? = this.accountManager.getAccount()
private fun HttpClientConfig<*>.configureRequest() {
defaultRequest {
url([email protected])
accept(ContentType.Application.Json)
contentType(ContentType.Application.Json)
}
}
private fun HttpClientConfig<*>.configureResponseValidator() {
HttpResponseValidator {
validateResponse { // Stub
when (it.status.value) {
in 300..399 -> throw ClientException(it.bodyAsText())
in 400..499 -> throw ClientException(it.bodyAsText())
in 500..599 -> throw ClientException(it.bodyAsText())
}
}
}
}
private fun HttpClientConfig<*>.installAuth() {
install(Auth) {
bearer {
sendWithoutRequest { request ->
val url = request.url.build().toString()
!(
url.contains("/api/oauth2/token")
|| (url.contains("/api/users") &&
request.method == HttpMethod.Post
)
)
}
loadTokens {
[email protected]?.let {
BearerTokens(accessToken = it.accessToken, refreshToken = it.refreshToken)
}
}
refreshTokens {
[email protected]?.let {
[email protected]()
BearerTokens(accessToken = it.accessToken, refreshToken = it.refreshToken)
}
}
}
}
}
private fun HttpClientConfig<*>.installContentNegotiation() {
install(ContentNegotiation) {
json()
}
}
private fun HttpClientConfig<*>.installLogging() {
install(Logging) {
logger = Logger.SIMPLE
level = LogLevel.ALL
}
}
override suspend fun getMe(): Profile {
return this.client.get("/api/users/me").body()
}
// And so on
}
Unfortunately, HttpClient
crashes sending a request by HTTPS
to a server with self-signed certificate:
On Android:
I/System.out: HttpClient: REQUEST https://xxx.xxx.xxx.xxx:xxx/api/oauth2/token failed with exception: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
On iOS:
Uncaught Kotlin exception: io.ktor.client.engine.darwin.DarwinHttpRequestException: Exception in http request: Error Domain=NSURLErrorDomain Code=-1202 "The certificate for this server is invalid. You might be connecting to a server that is pretending to be “xxx.xxx.xxx.xxx” which could put your confidential information at risk." UserInfo={NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, _kCFStreamErrorDomainKey=3, NSErrorPeerCertificateChainKey=(
"<cert(0x15704bc00) s: xxx.xxx.xxx.xxx i: xxx.xxx.xxx.xxx>"
How can I setup the Ktor client to trust a self-signed certificate?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论