了解 AlamoFire OAuth 示例

2024-02-06

我能够获得 AlamoFire 提供的 OAuth 示例的有效实现。但是,我希望了解某些代码行及其工作原理。

完整示例:

class OAuth2Handler: RequestAdapter, RequestRetrier {
    private typealias RefreshCompletion = (_ succeeded: Bool, _ accessToken: String?, _ refreshToken: String?) -> Void

    private let sessionManager: SessionManager = {
        let configuration = URLSessionConfiguration.default
        configuration.httpAdditionalHeaders = SessionManager.defaultHTTPHeaders

        return SessionManager(configuration: configuration)
    }()

    private let lock = NSLock()

    private var clientID: String
    private var baseURLString: String
    private var accessToken: String
    private var refreshToken: String

    private var isRefreshing = false
    private var requestsToRetry: [RequestRetryCompletion] = []

    // MARK: - Initialization

    public init(clientID: String, baseURLString: String, accessToken: String, refreshToken: String) {
        self.clientID = clientID
        self.baseURLString = baseURLString
        self.accessToken = accessToken
        self.refreshToken = refreshToken
    }

    // MARK: - RequestAdapter

    func adapt(_ urlRequest: URLRequest) throws -> URLRequest {
        if let urlString = urlRequest.url?.absoluteString, urlString.hasPrefix(baseURLString) {
            var urlRequest = urlRequest
            urlRequest.setValue("Bearer " + accessToken, forHTTPHeaderField: "Authorization")
            return urlRequest
        }

        return urlRequest
    }

    // MARK: - RequestRetrier

    func should(_ manager: SessionManager, retry request: Request, with error: Error, completion: @escaping RequestRetryCompletion) {
        lock.lock() ; defer { lock.unlock() }

        if let response = request.task?.response as? HTTPURLResponse, response.statusCode == 401 {
            requestsToRetry.append(completion)

            if !isRefreshing {
                refreshTokens { [weak self] succeeded, accessToken, refreshToken in
                    guard let strongSelf = self else { return }

                    strongSelf.lock.lock() ; defer { strongSelf.lock.unlock() }

                    if let accessToken = accessToken, let refreshToken = refreshToken {
                        strongSelf.accessToken = accessToken
                        strongSelf.refreshToken = refreshToken
                    }

                    strongSelf.requestsToRetry.forEach { $0(succeeded, 0.0) }
                    strongSelf.requestsToRetry.removeAll()
                }
            }
        } else {
            completion(false, 0.0)
        }
    }

    // MARK: - Private - Refresh Tokens

    private func refreshTokens(completion: @escaping RefreshCompletion) {
        guard !isRefreshing else { return }

        isRefreshing = true

        let urlString = "\(baseURLString)/oauth2/token"

        let parameters: [String: Any] = [
            "access_token": accessToken,
            "refresh_token": refreshToken,
            "client_id": clientID,
            "grant_type": "refresh_token"
        ]

        sessionManager.request(urlString, method: .post, parameters: parameters, encoding: JSONEncoding.default)
            .responseJSON { [weak self] response in
                guard let strongSelf = self else { return }

                if 
                    let json = response.result.value as? [String: Any], 
                    let accessToken = json["access_token"] as? String, 
                    let refreshToken = json["refresh_token"] as? String 
                {
                    completion(true, accessToken, refreshToken)
                } else {
                    completion(false, nil, nil)
                }

                strongSelf.isRefreshing = false
            }
    }
}

问题:

[weak self] succeeded, accessToken, refreshToken in
                    guard let strongSelf = self else { return }
  1. 目的是什么[weak self]guard for strongSelf?

        requestsToRetry.append(completion)
    
        if !isRefreshing {
            refreshTokens { [weak self] succeeded, accessToken, refreshToken in
                guard let strongSelf = self else { return }
    
                //Implementation
    
                strongSelf.requestsToRetry.forEach { $0(succeeded, 0.0) }
                strongSelf.requestsToRetry.removeAll()
            }
        }
    
  2. 这个请求重试是如何工作的?这requestsToRetry只是一个数组RequestRetryCompletion = (_ shouldRetry: Bool, _ timeDelay: TimeInterval)它如何知道哪些请求重试?

strongSelf.lock.lock()

  1. Does NSLock只是不允许self(OAuth2Handler) 在执行此方法时是否可以被任何其他线程访问?

1)正如Fonix所评论的,你有一个强烈的参考self以避免这种情况如果self为零,你开始收集保留周期..

我参考:

[weak self] ... in
guard let strongSelf = self else { return }

Since self将在异步分派的块中捕获,self换句话说,当块完成时将被隐式保留并再次释放self将被延长直到块完成后。编写此代码,您可以避免延长self并决定不执行该块,如果self等于零

2)根据你提到的几行:

if let response = request.task?.response as? HTTPURLResponse, response.statusCode == 401 {
            requestsToRetry.append(completion)
            ..

有一个数组叫做requestsToRetry其中包含重新启动所需的所有请求。在此代码中,您将所有具有以下内容的请求附加到数组中:401状态码(当服务器返回状态码401时) 用代码forEach你循环遍历requestToRetry array:

strongSelf.requestsToRetry.forEach { $0(succeeded, 0.0) }
strongSelf.requestsToRetry.removeAll()

并启动所有项目。循环结束后,您将删除所有项目。

事实上,消息来源报道称:

public typealias RequestRetryCompletion = (_ shouldRetry: Bool, _ timeDelay: TimeInterval) -> Void

public protocol RequestRetrier {
    func should(_ manager: SessionManager, retry request: Request, with error: Error, completion: @escaping RequestRetryCompletion)
}

您可以找到更多详细信息here https://github.com/Alamofire/Alamofire/blob/master/Documentation/Alamofire%204.0%20Migration%20Guide.md

3)正如您所说,经常面临的并发问题是与从不同线程访问/修改共享资源相关的问题。 这lock.lock()是一种在修改项目时锁定其他执行块的解决方案。代码在defer在离开解锁块的函数之前调用。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

了解 AlamoFire OAuth 示例 的相关文章

随机推荐