刷新承载令牌并使用AccessTokenPlugin

对于我的许多端点,我要求在请求中传递一个承载令牌,以对用户进行身份验证。因此,如果过期,我还需要刷新用户的令牌。

我发现this question是我的起点,但是我仍然不确定某些事情以及如何实现它们。

正如上述问题的答案所暗示的,我为MoyaProvider创建了一个扩展名:

extension MoyaProvider {
    convenience init(handleRefreshToken: Bool) {
        if handleRefreshToken {
            self.init(requestClosure: MoyaProvider.endpointResolver())
        } else {
            self.init()
        }
    }

    static func endpointResolver() -> MoyaProvider<Target>.RequestClosure {
        return { (endpoint,closure) in
            //Getting the original request
            let request = try! endpoint.urlRequest()

            //assume you have saved the existing token somewhere                
            if (#tokenIsnotExpired#) {                   
                // Token is valid,so just resume the original request
                closure(.success(request))
                return
            }

            //Do a request to refresh the authtoken based on refreshToken
            authenticationProvider.request(.refreshToken(params)) { result in
                switch result {
                case .success(let response):
                    let token = response.mapJSON()["token"]
                    let newRefreshToken = response.mapJSON()["refreshToken"]
                    //overwrite your old token with the new token
                    //overwrite your old refreshToken with the new refresh token

                    closure(.success(request)) // This line will "resume" the actual request,and then you can use accessTokenPlugin to set the Authentication header
                case .failure(let error):
                    closure(.failure(error)) //something went terrible wrong! Request will not be performed
                }
            }
    }
}

我还为TargetType创建了一个扩展名,如下所示:

import Moya

public protocol TargetTypeExtension: TargetType,accessTokenAuthorizable {}

public extension TargetTypeExtension {

    var baseURL: URL { return URL(string: Constants.apiUrl)! }

    var headers: [String: String]? { return nil }

    var method: Moya.Method { return .get }

    var authorizationType: AuthorizationType { return .bearer }

    var sampleData: Data { return Data() }
}

这是它的一种实现方式:

import Moya

public enum Posts {
    case likePost(postId: Int)
    case getcomments(postId: Int)
}

extension Posts: TargetTypeExtension {
    public var path: String {
        switch self {
        case .likePost(_): return "posts/like"
        case .getcomments(_): return "posts/comments"
        }
    }

    public var authorizationType: AuthorizationType {
        switch self {
        case .likePost(_): return .bearer
        case .getcomments(_): return .none
        }
    }

    public var method: Moya.Method {
        switch self {
        case .likePost,.getcomments:
            return .post
        }
    }

    public var task: Task {
        switch self {
        case let .likePost(postId):
            return .requestParameters(parameters: ["postId": postId],encoding: JSONEncoding.default)
        case let .getcomments(postId):
            return .requestParameters(parameters: ["postId": postId],encoding: JSONEncoding.default)
        }
    }
}

如您所见,我的likePost请求不需要承载令牌,而我的getcomments请求则不需要承载令牌。

所以我有几个问题:

  1. 我将如何修改我的MoyaProvider扩展名以使用Moya的accessTokenPluginfound here
  2. 如果针对特定请求的MoyaProviderAuthorizationType,我将如何修改我的.none扩展名以使其不需要承载令牌?

谢谢!

waruut 回答:刷新承载令牌并使用AccessTokenPlugin

我使用自定义moya提供程序和RxSwift做过,如果您使用的是RxSwift,则可以参考,它不会直接适合您的代码!

 extension Reactive where Base: MyMoyaProvider {
        func request(_ token: Base.Target,callbackQueue: DispatchQueue? = nil) -> Single<Response> {

    return Single.create { [weak base] single in

        var pandingCancelable:Cancellable?
        /// reschedule original request
        func reschedulCurrentRequest() {
            base?.saveRequest({
                pandingCancelable = base?.request(token,callbackQueue: callbackQueue,progress: nil) { result in
                    switch result {
                    case.success(let response):
                        single(.success(response))
                    case .failure(let error):
                        single(.error(error))
                    }
                }
            })
        }

        func refreshAccessToken(refreshToken:String) -> Cancellable? {
            base?.isRefreshing = true /// start retrieveing refresh token
            return base?.request(.retriveAccessToken(refreshToken: refreshToken),completion: { _ in
                base?.isRefreshing = false /// end retrieveing refresh token
                base?.executeAllSavedRequests()
            })
        }

        if (base?.isRefreshing ?? false) {
            reschedulCurrentRequest()
            return Disposables.create { pandingCancelable?.cancel() }
        }

        let cancellableToken = base?.request(token,progress: nil) { result in
            switch result {
            case let .success(response):
                if !(base?.isRefreshing ?? false),!token.isOAuth2TokenRefreshType,response.statusCode == TokenPlugin.CODE_UNAUTHORIZED,let refreshToken = token.getRefreshToken {
                    reschedulCurrentRequest()
                    _ = refreshAccessToken(refreshToken: refreshToken)
                } else if (base?.isRefreshing ?? false) {
                   reschedulCurrentRequest()
                } else {
                    single(.success(response))
                }
            case let .failure(error):
                single(.error(error))
            }
        }

        return Disposables.create {
            cancellableToken?.cancel()
        }
    }
}
}

CustomProvider:

class MyMoyaProvider: MoyaProvider<MyServices> {

var isRefreshing = false
private var pandingRequests: [DispatchWorkItem] = []

func saveRequest(_ block: @escaping () -> Void) {
    // Save request to DispatchWorkItem array
    pandingRequests.append( DispatchWorkItem {
        block()
    })
}

func executeAllSavedRequests() {
    pandingRequests.forEach({ DispatchQueue.global().async(execute: $0); })
    pandingRequests.removeAll()
}
}

extension TargetType {
    var isOAuth2TokenRefreshType: Bool { return false }
    var getRefreshToken:String? {  return nil }
}
本文链接:https://www.f2er.com/3076436.html

大家都在问