获得客户端证书使用Swift 3和Alamofire 4进行相互authentication
我想弄清楚如何使用Alamofire 4.0与Swift 3.0发送p12(我也有PEM证书和关键,如果需要的话)到网站进行身份validation。 我见过的所有例子都是针对Swift 2.0的,而不是我正在寻找的。 在我的Mac上的Safari浏览器中,我可以通过将p12放入钥匙链并在safari询问时发送它,以便我知道该部分可以工作。 我不知道是否有人可以用Alamofire 4.0和Swift 3.0的应用程序中的例子来帮助我。 证书也是自签名的。
任何想法或帮助? 我不只是寻找证书作为客户端密钥和证书需要被发送到服务器访问…
我能够得到它的工作。 一些问题已经解决了。 首先,您必须允许IOS接受自签名证书。 这需要设置AlamoFire serverTrustPolicy:
let serverTrustPolicies: [String: ServerTrustPolicy] = [ "your-domain.com": .disableEvaluation ] self.sessionManager = Alamofire.SessionManager( serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies) )
从那里,你必须重写sessionDidRecieveChallenge发送客户端证书。 因为我想使用一个p12文件,我修改了我在其他地方find的一些代码(对不起,我没有源代码),使Swift 3.0使用基础类导入p12:
import Foundation public class PKCS12 { var label:String? var keyID:Data? var trust:SecTrust? var certChain:[SecTrust]? var identity:SecIdentity? let securityError:OSStatus public init(data:Data, password:String) { //self.securityError = errSecSuccess var items:CFArray? let certOptions:NSDictionary = [kSecImportExportPassphrase as NSString:password as NSString] // import certificate to read its entries self.securityError = SecPKCS12Import(data as NSData, certOptions, &items); if securityError == errSecSuccess { let certItems:Array = (items! as Array) let dict:Dictionary<String, AnyObject> = certItems.first! as! Dictionary<String, AnyObject>; self.label = dict[kSecImportItemLabel as String] as? String; self.keyID = dict[kSecImportItemKeyID as String] as? Data; self.trust = dict[kSecImportItemTrust as String] as! SecTrust?; self.certChain = dict[kSecImportItemCertChain as String] as? Array<SecTrust>; self.identity = dict[kSecImportItemIdentity as String] as! SecIdentity?; } } public convenience init(mainBundleResource:String, resourceType:String, password:String) { self.init(data: NSData(contentsOfFile: Bundle.main.path(forResource: mainBundleResource, ofType:resourceType)!)! as Data, password: password); } public func urlCredential() -> URLCredential { return URLCredential( identity: self.identity!, certificates: self.certChain!, persistence: URLCredential.Persistence.forSession); } }
这将允许我导入文件,并将其发送回客户端。
let cert = PKCS12.init(mainBundleResource: "cert", resourceType: "p12", password: "password"); self.sessionManager.delegate.sessionDidReceiveChallenge = { session, challenge in if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodClientCertificate { return (URLSession.AuthChallengeDisposition.useCredential, self.cert.urlCredential()); } if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust { return (URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust: challenge.protectionSpace.serverTrust!)); } return (URLSession.AuthChallengeDisposition.performDefaultHandling, Optional.none); }
现在,您可以使用sessionManager根据需要创build多个呼叫。
请注意,我还在info.plist中添加了以下内容作为build议,以解决新的iOSfunction中的新安全function:
<key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key> <true/> <key>NSExceptionDomains</key> <dict> <key>your-domain.com</key> <dict> <key>NSIncludesSubdomains</key> <true/> <key>NSExceptionRequiresForwardSecrecy</key> <false/> <key>NSExceptionAllowsInsecureHTTPLoads</key> <true/> </dict> </dict> </dict>
我希望这有帮助!
这是我的例子,可能会帮助某人(Alamofire 4.0,Swift 3,xCode 8)
import Alamofire class NetworkConnection { let developmentDomain = Config.developmentDomain // "api.myappdev.com" let productionDomain = Config.productionDomain // "api.myappprod.com" let certificateFilename = Config.certificateFilename // "godaddy" let certificateExtension = Config.certificateExtension // "der" let useSSL = true var manager: SessionManager! var serverTrustPolicies: [String : ServerTrustPolicy] = [String:ServerTrustPolicy]() static let sharedManager = NetworkConnection() init(){ if useSSL { manager = initSafeManager() } else { manager = initUnsafeManager() } } //USED FOR SITES WITH CERTIFICATE, OTHERWISE .DisableEvaluation func initSafeManager() -> SessionManager { setServerTrustPolicies() manager = SessionManager(configuration: URLSessionConfiguration.default, delegate: SessionDelegate(), serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)) return manager } //USED FOR SITES WITHOUT CERTIFICATE, DOESN'T CHECK FOR CERTIFICATE func initUnsafeManager() -> SessionManager { manager = Alamofire.SessionManager.default manager.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!) //URLCredential(forTrust: challenge.protectionSpace.serverTrust!) } else { if challenge.previousFailureCount > 0 { disposition = .cancelAuthenticationChallenge } else { credential = self.manager.session.configuration.urlCredentialStorage?.defaultCredential(for: challenge.protectionSpace) if credential != nil { disposition = .useCredential } } } return (disposition, credential) } return manager } func setServerTrustPolicies() { let pathToCert = Bundle.main.path(forResource: certificateFilename, ofType: certificateExtension) let localCertificate:Data = try! Data(contentsOf: URL(fileURLWithPath: pathToCert!)) let serverTrustPolicies: [String: ServerTrustPolicy] = [ productionDomain: .pinCertificates( certificates: [SecCertificateCreateWithData(nil, localCertificate as CFData)!], validateCertificateChain: true, validateHost: true ), developmentDomain: .disableEvaluation ] self.serverTrustPolicies = serverTrustPolicies } static func addAuthorizationHeader (_ token: String, tokenType: String) -> [String : String] { let headers = [ "Authorization": tokenType + " " + token ] return headers } }
添加以下到您的Info.plist
<key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key> <true/> <key>NSExceptionDomains</key> <dict> <key>api.myappdev.com</key> <dict> <key>NSExceptionAllowsInsecureHTTPLoads</key> <true/> <key>NSExceptionRequiresForwardSecrecy</key> <false/> <key>NSIncludesSubdomains</key> <true/> <key>NSRequiresCertificateTransparency</key> <false/> <key>NSTemporaryExceptionMinimumTLSVersion</key> <string>TLSv1.2</string> </dict> </dict> </dict>
这里是一个请求的例子
import Alamofire class ActionUserUpdate { let url = "https://api.myappdev.com/v1/" let manager = NetworkConnection.sharedManager.manager func updateUser(_ token: String, tokenType: String, expiresIn: Int, params: [String : String]) { let headers = NetworkConnection.addAuthorizationHeader(token, tokenType: tokenType) manager?.request(url, method: .put, parameters: params, encoding: JSONEncoding.default, headers: headers).responseJSON { response in print(response.description) print(response.debugDescription) print(response.request) // original URL request print(response.response) // URL response print(response.data) // server data print(response.result) // result of response serialization } } }
- Swift 3 – Alamofilre 4.0多部分图像上传与进展
- 无法从IPv6连接到IPv4错误域= NSURLErrorDomain代码= -1003“无法find具有指定主机名的服务器
- 使用Alamofire快速检查互联网连接
- Alamofire Multipart与参数:从UIImagePickerController Swift上传图像
- “没有这样的模块”Alamofire“”Xcode不会识别Alamofire框架
- 使用Alamofire在iOS上使用证书固定的网络安全
- 模块“Alamofire”没有名为“请求”的成员
- 使用URLRequestConvertible在unit testing中链接错误
- 我们如何在Swift中嵌套JSON参数上传多部分表单数据?