如何让 Apollo Client iOS 接受自签名证书
How to Make Apollo Client iOS Accept Self-Signed Certificates
如何让 ApolloClient 接受自签名证书?我们将它用于内部应用程序,并且由于认证问题,对 GraphQL 端点的调用失败。我在存储库问题中找到了 this thread,但自那次讨论以来,API 似乎已经发生了一些变化,而正确的当前方法让我望而却步。
目前,我的集成测试下降到 .failure
分支报告证书验证问题:
let apollo = AppConstants.current.apollo
apollo.fetch( query: DriverStatementsIncompleteQuery( onepass: "test-user" ) ) { result in
switch result {
case .success( let results ):
print( results )
XCTAssertNil( results.errors )
self.completedExpectation.fulfill()
case .failure( let error ):
XCTFail( error.localizedDescription )
self.completedExpectation.fulfill()
}
}
wait( for: [self.completedExpectation], timeout: 5 )
Apollo iOS 团队的 Ellen Shapiro 非常友善地为我指明了正确的方向。这是我最终得到的结果:
public struct PromiscuousApolloClientFactory {
/// Creates an `ApolloClient` instance that is configured to work with certificates that the
/// OS would otherwise deem invalid, like those that are self-signed.
/// - Parameter endpointURL: The URL of the GraphQL endpoint.
/// - Returns: The configured `ApolloClient` instance.
public static func make( with endpointURL: URL ) -> ApolloClient {
let store = ApolloStore( cache: InMemoryNormalizedCache() )
let sessionConfig = URLSessionConfiguration.default
let client = PromiscuousURLSessionClient( sessionConfiguration: sessionConfig )
let provider = LegacyInterceptorProvider( client: client, store: store )
let transport = RequestChainNetworkTransport( interceptorProvider: provider, endpointURL: endpointURL )
return ApolloClient( networkTransport: transport, store: store )
}
}
private class PromiscuousURLSessionClient: URLSessionClient {
override func urlSession( _ session: URLSession,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: @escaping ( URLSession.AuthChallengeDisposition, URLCredential? ) -> Void ) {
let protectionSpace = challenge.protectionSpace
guard protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust,
let serverTrust = protectionSpace.serverTrust else {
completionHandler( .performDefaultHandling, nil )
return
}
let credential = URLCredential( trust: serverTrust )
completionHandler( .useCredential, credential )
}
}
注意好处:这通常是一种不好的做法,因为它会短路为您自身提供的安全保护。如果您有使用 OS 可以验证的证书的路径,请改为执行此操作。 :)
如何让 ApolloClient 接受自签名证书?我们将它用于内部应用程序,并且由于认证问题,对 GraphQL 端点的调用失败。我在存储库问题中找到了 this thread,但自那次讨论以来,API 似乎已经发生了一些变化,而正确的当前方法让我望而却步。
目前,我的集成测试下降到 .failure
分支报告证书验证问题:
let apollo = AppConstants.current.apollo
apollo.fetch( query: DriverStatementsIncompleteQuery( onepass: "test-user" ) ) { result in
switch result {
case .success( let results ):
print( results )
XCTAssertNil( results.errors )
self.completedExpectation.fulfill()
case .failure( let error ):
XCTFail( error.localizedDescription )
self.completedExpectation.fulfill()
}
}
wait( for: [self.completedExpectation], timeout: 5 )
Apollo iOS 团队的 Ellen Shapiro 非常友善地为我指明了正确的方向。这是我最终得到的结果:
public struct PromiscuousApolloClientFactory {
/// Creates an `ApolloClient` instance that is configured to work with certificates that the
/// OS would otherwise deem invalid, like those that are self-signed.
/// - Parameter endpointURL: The URL of the GraphQL endpoint.
/// - Returns: The configured `ApolloClient` instance.
public static func make( with endpointURL: URL ) -> ApolloClient {
let store = ApolloStore( cache: InMemoryNormalizedCache() )
let sessionConfig = URLSessionConfiguration.default
let client = PromiscuousURLSessionClient( sessionConfiguration: sessionConfig )
let provider = LegacyInterceptorProvider( client: client, store: store )
let transport = RequestChainNetworkTransport( interceptorProvider: provider, endpointURL: endpointURL )
return ApolloClient( networkTransport: transport, store: store )
}
}
private class PromiscuousURLSessionClient: URLSessionClient {
override func urlSession( _ session: URLSession,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: @escaping ( URLSession.AuthChallengeDisposition, URLCredential? ) -> Void ) {
let protectionSpace = challenge.protectionSpace
guard protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust,
let serverTrust = protectionSpace.serverTrust else {
completionHandler( .performDefaultHandling, nil )
return
}
let credential = URLCredential( trust: serverTrust )
completionHandler( .useCredential, credential )
}
}
注意好处:这通常是一种不好的做法,因为它会短路为您自身提供的安全保护。如果您有使用 OS 可以验证的证书的路径,请改为执行此操作。 :)