我正在尝试通过https为我的iOS应用程序使用Web服务。 Web服务器使用自签名证书。
在使用网络服务时,我收到错误“证书无效”。
FAILURE:Error Domain = NSURLErrorDomain Code = -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和端口号一起使用,我在我的etc / hosts文件中为Web服务器IP创建了一个主机条目,并像https://devportal:8443/rest/login一样使用它,而不是像{{{{}}那样使用它。 3}}
我已经关注了服务器信任策略的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 :(得分:10)
我修改了我的代码,如下所示。我提到https://sourceforge.net/projects/gnuplot/files/gnuplot/5.0.4/来解决这个问题。
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服务器, 通过在etc / hosts中添加主机条目将IP地址映射到域 在您的mac中使用文件,然后使用NSExceptionDomains中的域名
重要提示:请勿在生产中使用此代码,因为这会影响您的用户 通过绕过auth挑战来处理风险信息。
答案 1 :(得分:0)
不建议用于生产用例
//Use this manager class
class APIManager {
static var Manager: Alamofire.Session = {
let manager = ServerTrustManager(evaluators: ["your endpoint": DisabledTrustEvaluator()])
let session = Session(serverTrustManager: manager)
return session
}()
}
//Call APIs using this manager
APIManager.Manager.request("API")