2016-11-23 116 views
3

我試圖通過https爲我的iOS應用程序使用Web服務。 Web服務器使用自簽名證書。Alamofire 4.0證書無效問題

使用Web服務時,出現錯誤「證書無效」。

失敗:「它可以把您的機密信息處於危險之中‘錯誤域= NSURLErrorDomain代碼= -1202’此服務器的證書無效,您可能正在連接到一個僞裝成是服務器」門戶網站

我知道最好的做法是在服務器端修復這個問題,以啓用受信任的根CA.但是,由於這是一個臨時開發環境,我們正在使用自簽名證書。 由於這是ATS問題,我已經在我的info.plist中編輯了ATS,如下所示。

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> 
<plist version="1.0"> 
<dict> 
    <key>NSExceptionDomains</key> 
    <dict> 
     <key>devportal</key> 
     <dict> 
      <key>NSTemporaryExceptionMinimumTLSVersion</key> 
      <string>TLSv1.2</string> 
      <key>NSIncludesSubdomains</key> 
      <true/> 
      <key>NSExceptionRequiresForwardSecrecy</key> 
      <false/> 
      <key>NSExceptionAllowsInsecureHTTPLoads</key> 
      <true/> 
     </dict> 
    </dict> 
    <key>NSAllowsArbitraryLoads</key> 
    <false/> 
</dict> 
</plist> 

由於NSException域不會與IP和端口號的工作,我已經創造了我等主機條目/ hosts文件的Web服務器IP和https://192.22.xx.xxx:8443/rest/login

消耗它像 https://devportal:8443/rest/login不是消耗它的

我遵循關於服務器信任策略的alamofire文檔,編輯了ATS以允許異常域,但沒有爲我解決。我已經在這個問題上花了3天時間。我錯過了什麼嗎?有人遇到過類似的問題嗎?有沒有解決方案?在此先感謝

我使用almofire 4.0,Xcode 8.0。以下是我的代碼。

class LoginService{ 
    private static var Manager: Alamofire.SessionManager = { 

      let pathToCert = Bundle.main.path(forResource: "192.22.xx.xxx", ofType: "crt") // Downloaded this certificate and have added to my bundle 
      let localCertificate:NSData = NSData(contentsOfFile: pathToCert!)! 

      // Create the server trust policies 
      let serverTrustPolicies: [String: ServerTrustPolicy] = [ 
       "192.22.xx.xxx": .pinCertificates(
        certificates: [SecCertificateCreateWithData(nil, localCertificate)!], 
        validateCertificateChain: true, 
        validateHost: true 
       ), 

       "devportal:8443": .disableEvaluation 
      ] 

      // Create custom manager 
      let configuration = URLSessionConfiguration.default 
      configuration.httpAdditionalHeaders = Alamofire.SessionManager.defaultHTTPHeaders 
      let manager = Alamofire.SessionManager(
       configuration: URLSessionConfiguration.default, 
       serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies) 
     ) 

      return manager 
    }() 



    /** 
     Calls the Login Web Service to authenticate the user 
     */ 
    public func login(username:String, password: String){ 

      let parameters = [ 
       "username": "TEST", 
       "password": "PASSWORD", 
        ] 
      let header: HTTPHeaders = ["Accept": "application/json"] 
      LoginService.Manager.request("https://devportal:8443/rest/login", method: .post, parameters: parameters, encoding: JSONEncoding(options: []),headers :header).responseJSON { response in 
       debugPrint(response) 

       if let json = response.result.value { 
        print("JSON: \(json)") 
       } 
      } 



    } 
} 
+0

您的測試設備是否配置爲信任自簽名證書?這可以在iOS設置 - >常規 - >配置文件中驗證。 –

+0

@Rein我沒有在設備上測試它,因爲它沒有測試準備好。我剛開始開發並在模擬器上運行它。 – CrazyDeveloper

回答

3

我修改了我的代碼,如下所示,它工作。我提到了Swift: How to Make Https Request Using Server SSL Certificate來解決這個問題。

 class LoginService{ 
      private static var Manager: Alamofire.SessionManager = { 

        // Create the server trust policies 
        let serverTrustPolicies: [String: ServerTrustPolicy] = [ 

         "devportal:8443": .disableEvaluation 
        ] 

        // Create custom manager 
        let configuration = URLSessionConfiguration.default 
        configuration.httpAdditionalHeaders = Alamofire.SessionManager.defaultHTTPHeaders 
        let manager = Alamofire.SessionManager(
         configuration: URLSessionConfiguration.default, 
         serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies) 
       ) 

        return manager 
      }() 



      /** 
       Calls the Login Web Service to authenticate the user 
       */ 
      public func login(username:String, password: String){ 

    // Handle Authentication challenge 

      let delegate: Alamofire.SessionDelegate = LoginService.Manager.delegate 
     delegate.sessionDidReceiveChallenge = { session, challenge in 
       var disposition: URLSession.AuthChallengeDisposition = .performDefaultHandling 
       var credential: URLCredential? 
       if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust { 
        disposition = URLSession.AuthChallengeDisposition.useCredential 
        credential = URLCredential(trust: challenge.protectionSpace.serverTrust!) 
       } else { 
        if challenge.previousFailureCount > 0 { 
         disposition = .cancelAuthenticationChallenge 
        } else { 
         credential = LoginService.Manager.session.configuration.urlCredentialStorage?.defaultCredential(for: challenge.protectionSpace) 
         if credential != nil { 
          disposition = .useCredential 
         } 
        } 
       } 
       return (disposition, credential) 
     } 

//Web service Request  
        let parameters = [ 
         "username": "TEST", 
         "password": "PASSWORD", 
          ] 
        let header: HTTPHeaders = ["Accept": "application/json"] 
        LoginService.Manager.request("https://devportal:8443/rest/login", method: .post, parameters: parameters, encoding: JSONEncoding(options: []),headers :header).responseJSON { response in 
         debugPrint(response) 

         if let json = response.result.value { 
          print("JSON: \(json)") 
         } 
        } 



      } 
     } 

你也應該配置的plist如下

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> 
<plist version="1.0"> 
<dict> 
    <key>NSExceptionDomains</key> 
    <dict> 
     <key>devportal</key> 
     <dict> 
      <key>NSTemporaryExceptionMinimumTLSVersion</key> 
      <string>TLSv1.2</string> 
      <key>NSIncludesSubdomains</key> 
      <true/> 
      <key>NSExceptionRequiresForwardSecrecy</key> 
      <false/> 
      <key>NSExceptionAllowsInsecureHTTPLoads</key> 
      <true/> 
     </dict> 
    </dict> 
    <key>NSAllowsArbitraryLoads</key> 
    <false/> 
</dict> 
</plist> 

在NSExceptiondomains不要輸入IP或端口號。它不會 工作。如果你試圖連接到IP地址爲Web服務器, 在你的Mac將在等一個主機條目/主機 文件映射IP地址到域,然後在NSExceptionDomains

重要使用的域名:不要在生產中使用此代碼,因爲這會讓您的用戶繞過認證挑戰而面臨風險。

+0

非常感謝我的工作:-) –