Alamofire 5.0 双向认证

双向认证分为两方向的认证:

  1. 客户端认证服务端;
  2. 服务端认证客户端;

以下逐个说明:

认证服务器

认证服务器分为:

  1. DefaultTrustEvaluator,使用默认的验证方式,验证证书的有效性,证书信任链那套
  2. RevocationTrustEvaluator,验证证书是否被吊销
  3. PinnedCertificatesTrustEvaluator,验证证书是否同本地的一致,可以是自签证书
  4. PublicKeysTrustEvaluator,验证证书的公钥,可以是自签证书,不过这个有个好处就是不用关心证书的有效期了
  5. CompositeTrustEvaluator,混合模式
  6. DisabledTrustEvaluator,不验证证书

我们目前使用的是验证公钥,以此为例:

// 验证服务器的公钥
// 默认获取了 cer 结尾的文件,只需要把证书放到项目里边就行了,不需要显示指定
let trustManager = ServerTrustManager(evaluators: [
    M_NodeServerUrl: PublicKeysTrustEvaluator()
])
let session = Session(serverTrustManager: trustManager)
               
// 请求的时候直接使用
session.request(xxxx)...
认证客户端

认证客户端是通过 nsurl 协议来完成的,这部分其实不完全算是 Alamofire 的行为,可以通过继承 SessionDelegate 类,然后重写方法
func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) 来实现。
具体代码如下:

class WSSessionDelegate: SessionDelegate {
    override func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
        switch challenge.protectionSpace.authenticationMethod {
        case NSURLAuthenticationMethodClientCertificate:
        	// 获取证书
            guard let file = Bundle.main.path(forResource: "client", ofType: "p12"),
                  let p12Data = try? Data.init(contentsOf: URL.init(string: file)!) else {
                
                completionHandler(.performDefaultHandling, nil)
                return
            }
            
            let p12Contents = PKCS12(pkcs12Data: p12Data, password: "xxxx")
            guard let identity = p12Contents.identity else {
                completionHandler(.performDefaultHandling, nil)
                return
            }
            
            let credential = URLCredential(identity: identity,
                                           certificates: nil,
                                           persistence: .none)
            challenge.sender?.use(credential, for: challenge)
            completionHandler(.useCredential, credential)
        default:
            completionHandler(.performDefaultHandling, nil)
        }
    }
    
    private class PKCS12 {
        let label: String?
        let keyID: NSData?
        let trust: SecTrust?
        let certChain: [SecTrust]?
        let identity: SecIdentity?
        
        /// Creates a PKCS12 instance from a piece of data.
        /// - Parameters:
        ///   - pkcs12Data: the actual data we want to parse.
        ///   - password: The password required to unlock the PKCS12 data.
        public init(pkcs12Data: Data, password: String) {
            let importPasswordOption: NSDictionary
                = [kSecImportExportPassphrase as NSString: password]
            var items: CFArray?
            let secError: OSStatus
                = SecPKCS12Import(pkcs12Data as NSData,
                                  importPasswordOption, &items)
            guard secError == errSecSuccess else {
                if secError == errSecAuthFailed {
                    NSLog("Incorrect password?")
                    
                }
                fatalError("Error trying to import PKCS12 data")
            }
            guard let theItemsCFArray = items else { fatalError() }
            let theItemsNSArray: NSArray = theItemsCFArray as NSArray
            guard let dictArray
                    = theItemsNSArray as? [[String: AnyObject]] else {
                fatalError()
            }
            func f<T>(key: CFString) -> T? {
                for dict in dictArray {
                    if let value = dict[key as String] as? T {
                        return value
                    }
                }
                return nil
            }
            self.label = f(key: kSecImportItemLabel)
            self.keyID = f(key: kSecImportItemKeyID)
            self.trust = f(key: kSecImportItemTrust)
            self.certChain = f(key: kSecImportItemCertChain)
            self.identity = f(key: kSecImportItemIdentity)
        }
    }
}

let session = Session(delegate: WSSessionDelegate())
// 请求的时候直接使用
session.request(xxxx)...

两个结合起来可以是

let session = Session(delegate: WSSessionDelegate(), serverTrustManager: trustManager)

官方参考文档

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xyccstudio

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值