【问题标题】:The certificate is invalid when connecting iOS app to an api running on localhost with Alamofire使用 Alamofire 将 iOS 应用程序连接到在 localhost 上运行的 api 时证书无效
【发布时间】:2017-11-21 03:28:50
【问题描述】:

我正在尝试连接到在 localhost 上运行的 API,以便可以在 iOS 模拟器中测试我的应用程序。我来了

NSLocalizedDescription=此服务器的证书无效。 您可能正在连接到伪装成“127.0.0.1”的服务器 这可能会使您的机密信息面临风险。 NSErrorFailingURLKey=https://127.0.0.1:8000/post/, NSErrorFailingURLStringKey=https://127.0.0.1:8000/post/, NSErrorClientCertificateStateKey=0

我正在使用 AlamofireThis similar question 没有帮助。与旧版本的 Alamofire 相比,它似乎已经过时了。

我的 info.plist 已经包含

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
</dict>

如何暂时禁用证书要求,以便在 localhost 上测试我的应用程序?

这是我在更改服务器信任策略后的代码,如其中一个答案所建议的那样

视图控制器:

class TableViewController: UIViewController {
    let postClient = PostServiceClient.sharedInstance

    override func viewDidLoad() {
        super.viewDidLoad()
        postClient.getPosts()
    }
}

PostServiceClient:

import Alamofire

class PostServiceClient {

    static let sharedInstance: PostServiceClient = PostServiceClient()

    var sessionManager : SessionManager!

    init() {
        let serverTrustPolicies: [String: ServerTrustPolicy] = [
            "https://127.0.0.1:8000/" : .disableEvaluation
        ]

        self.sessionManager =  SessionManager(configuration: URLSessionConfiguration.default,
                                              serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)
        )
    }
    static let url = URL.init(string: "https://127.0.0.1:8000/post/")

    // Method to get posts from the wall
    func getPosts(){
        print("Getting posts with completion handler")
        var request = URLRequest(url: PostServiceClient.url!)
        request.httpMethod = "GET"
        self.sessionManager.request(request).responseJSON { (response) in
            guard response.result.isSuccess else {
                print("Error while getting posts: \(String(describing: response.result.error))")
                return
            }
            guard let responseJSON = response.result.value as? [String: Any],
                let results = responseJSON["results"] as? [[String: Any]] else {
                print("Invalid response recieved from service")
                return
            }
            print(responseJSON)
        }

    }
}

这是我得到的完整输出:

使用完成处理程序 2017-06-19 14:22:15.770616-0400 获取帖子 WallAppiOS[28605:9092279] [] nw_coretls_callback_handshake_message_block_invoke_3 tls_handshake_continue:[-9812] 2017-06-19 14:22:15.770 WallAppiOS[28605:9092321] NSURLSession/NSURLConnection HTTP 加载 failed (kCFStreamErrorDomainSSL, -9813) 获取帖子时出错: 可选(错误域=NSURLErrorDomain 代码=-1202 "证书为 此服务器无效。您可能正在连接的服务器是 假装是“127.0.0.1”,这可能会使您的机密 有风险的信息。" UserInfo={NSLocalizedDescription=证书 此服务器无效。您可能正在连接到一个服务器 冒充“127.0.0.1”,这可能会使您的机密 有风险的信息。, NSLocalizedRecoverySuggestion=您是否愿意 还是连接到服务器?, _kCFStreamErrorDomainKey=3, NSUnderlyingError=0x7a3627c0 {错误域=kCFErrorDomainCFNetwork 代码=-1202“(空)” UserInfo={_kCFStreamPropertySSLClientCertificateState=0, _kCFNetworkCFStreamSSLErrorOriginalValue=-9813, _kCFStreamErrorCodeKey=-9813, _kCFStreamErrorDomainKey=3, kCFStreamPropertySSLPeerTrust=, kCFStreamPropertySSLPeerCertificates=( "" )}}, _kCFStreamErrorCodeKey=-9813, NSErrorFailingURLStringKey=https://127.0.0.1:8000/post/, NSErrorPeerCertificateChainKey=( "" ), NSErrorClientCertificateStateKey=0, NSURLErrorFailingURLPeerTrustErrorKey=, NSErrorFailingURLKey=https://127.0.0.1:8000/post/})

【问题讨论】:

  • 如何获得服务器证书?看起来你必须关闭 Alamofire 中的证书检查。 ATS 要求您不要使用 HTTP,但它与证书无关。证书检查是从根证书开始的链
  • @Wingzero 你知道如何关闭证书检查吗?
  • 不是真的,但你可以寻找信任策略设置或搜索开关

标签: ios ssl alamofire


【解决方案1】:

在这个例子中,我使用serverTrustPolicyManager 来处理与 ssl 未认证服务器的连接,我使用单例来处理我的应用程序中的所有连接,您必须声明 sessionManager,如 Alamofire github 页面所述

确保保留对新 SessionManager 实例的引用, 否则,当您的 sessionManager 被释放。

    class exampleNetworkClient {

        static let sharedInstance: exampleNetworkClient = exampleNetworkClient()

        var sessionManager : SessionManager?

        init() {
            let serverTrustPolicies: [String: ServerTrustPolicy] = [
                "https://127.0.0.1:8000" : .disableEvaluation 
            ]

            self.sessionManager =  SessionManager(configuration: URLSessionConfiguration.default,
                                  serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)
            )
        }

        static let portalUrl = URL.init(string:"https://127.0.0.1:8000/exampleserviceUrl")

    func exampleMethod()
    {
        var request = URLRequest(url: iOSETKClient.portalUrl!)
        request.httpMethod = "GET"

        //Important Note that you need to use your custom session manager
        self.sessionManager!.request(request).responseString { (response) in
            ///...RESPONSE LOGIC...///

        }
    }
}

希望对你有帮助

【讨论】:

  • @MatthewDrill 我会尝试用 node 安装一个本地服务器并测试它,我会发布我的结果
【解决方案2】:

我是通过将 ReinerMelian 的答案与另一个问题中的一个答案结合起来实现的

视图控制器:

class TableViewController: UIViewController {

    let postClient = PostServiceClient.sharedInstance

    override func viewDidLoad() {
        super.viewDidLoad()

        postClient.sessionManager.delegate.sessionDidReceiveChallenge = { session, challenge in
            var disposition: URLSession.AuthChallengeDisposition = .performDefaultHandling
            var credential: URLCredential?

            if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust, let trust = challenge.protectionSpace.serverTrust {
                disposition = URLSession.AuthChallengeDisposition.useCredential
                credential = URLCredential(trust: trust)
            } else {
                if challenge.previousFailureCount > 0 {
                    disposition = .cancelAuthenticationChallenge
                } else {
                    credential = self.postClient.sessionManager.session.configuration.urlCredentialStorage?.defaultCredential(for: challenge.protectionSpace)

                    if credential != nil {
                        disposition = .useCredential
                    }
                }
            }

            return (disposition, credential)
        }

        postClient.getPosts()
    }
}

服务客户:

class PostServiceClient {

    static let sharedInstance: PostServiceClient = PostServiceClient()

    var sessionManager : SessionManager!

    init() {
        self.sessionManager =  SessionManager(configuration: URLSessionConfiguration.default)
    }
    static let url = URL.init(string: "https://127.0.0.1:8000/post/")

    // Methods to get posts from the wall
    func getPosts(){
        print("Getting posts with completion handler")
        var request = URLRequest(url: PostServiceClient.url!)
        request.httpMethod = "GET"
        self.sessionManager.request(request).responseJSON { (response) in
            guard response.result.isSuccess else {
                print("Error while getting posts: \(String(describing: response.result.error))")
                return
            }
            guard let responseJSON = response.result.value as? [String: Any],
                let results = responseJSON["results"] as? [[String: Any]] else {
                print("Invalid response recieved from service")
                return
            }
            print(responseJSON)
        }

    }
}

【讨论】:

  • 我很高兴看到你想通了,恭喜!
猜你喜欢
  • 2011-12-24
  • 2021-10-24
  • 2013-09-13
  • 1970-01-01
  • 1970-01-01
  • 2015-07-21
  • 2014-08-19
  • 1970-01-01
  • 2021-09-20
相关资源
最近更新 更多