刷新令牌的正确方法 [英] Right way to refresh the token

查看:34
本文介绍了刷新令牌的正确方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

RequestManager 类 中有一个函数 getUser 在我的 VC 中调用.

There is a function getUser in RequestManager class that called in my VC.

func getUser(onCompletion: @escaping (_ result: User?, error: String?) -> Void) {
    Alamofire.request(Router.getUser).responseJSON { (response) in
        // here is the work with response
    }
}

如果此请求返回 403,则表示 access_token 已过期.我需要刷新令牌并重复来自我的 VC 的请求.

If this request returns 403 it means access_token is expired. I need to refresh token and repeat the request from my VC.

现在是问题.

如何以正确的方式刷新令牌并重复请求?

How to refresh token and repeat the request in the right way?

MyViewControllergetUser 方法中处理错误和刷新令牌不是一个好主意,因为我有很多VCs请求方法.

To handle the error and refresh token in MyViewController or getUser method is not good idea because I have a lot of VCs and request methods.

我需要类似的东西:VC 调用该方法并获取 User 即使令牌已过期并且 refreshToken 必须 在所有请求方法中.

I need something like: VC calls the method and gets the User even if token is expired and refreshToken must not be in all request methods.

编辑

refreshToken 方法

func refreshToken(onCompletion: @escaping (_ result: Bool?) -> Void) {
    Alamofire.request(Router.refreshToken).responseJSON { (response) in
        print(response)
        if response.response?.statusCode == 200 {
            guard let data = response.data else { return onCompletion(false) }
            let token = try? JSONDecoder().decode(Token.self, from: data)
            token?.setToken()
            onCompletion(true)
        } else {
            onCompletion(false)
        }
    }
}

推荐答案

为了解决这个问题,我创建了一个类,我们将从中调用每个 API,比如 BaseService.swift.

To solve this, I created a class from which we will call every API, say BaseService.swift.

BaseService.swift :

import Foundation
import Alamofire
import iComponents

struct AlamofireRequestModal {
    var method: Alamofire.HTTPMethod
    var path: String
    var parameters: [String: AnyObject]?
    var encoding: ParameterEncoding
    var headers: [String: String]?

    init() {
        method = .get
        path = ""
        parameters = nil
        encoding = JSONEncoding() as ParameterEncoding
        headers = ["Content-Type": "application/json",
                   "X-Requested-With": "XMLHttpRequest",
                   "Cache-Control": "no-cache"]
    }
}

class BaseService: NSObject {

    func callWebServiceAlamofire(_ alamoReq: AlamofireRequestModal, success: @escaping ((_ responseObject: AnyObject?) -> Void), failure: @escaping ((_ error: NSError?) -> Void)) {

        // Create alamofire request
        // "alamoReq" is overridden in services, which will create a request here
        let req = Alamofire.request(alamoReq.path, method: alamoReq.method, parameters: alamoReq.parameters, encoding: alamoReq.encoding, headers: alamoReq.headers)

        // Call response handler method of alamofire
        req.validate(statusCode: 200..<600).responseJSON(completionHandler: { response in
            let statusCode = response.response?.statusCode

            switch response.result {
            case .success(let data):

                if statusCode == 200 {
                    Logs.DLog(object: "\n Success: \(response)")
                    success(data as AnyObject?)

                } else if statusCode == 403 {
                    // Access token expire
                    self.requestForGetNewAccessToken(alaomReq: alamoReq, success: success, failure: failure)

                } else {
                    let errorDict: [String: Any] = ((data as? NSDictionary)! as? [String: Any])!
                    Logs.DLog(object: "\n \(errorDict)")
                    failure(errorTemp as NSError?)
                }
            case .failure(let error):
                Logs.DLog(object: "\n Failure: \(error.localizedDescription)")
                failure(error as NSError?)
            }
        })
    }

}

extension BaseService {

    func getAccessToken() -> String {
        if let accessToken =  UserDefaults.standard.value(forKey: UserDefault.userAccessToken) as? String {
            return "Bearer " + accessToken
        } else {
            return ""
        }
    }

    // MARK: - API CALL
    func requestForGetNewAccessToken(alaomReq: AlamofireRequestModal, success: @escaping ((_ responseObject: AnyObject?) -> Void), failure: @escaping ((_ error: NSError?) -> Void) ) {

        UserModal().getAccessToken(success: { (responseObj) in
            if let accessToken = responseObj?.value(forKey: "accessToken") {
                UserDefaults.standard.set(accessToken, forKey: UserDefault.userAccessToken)
            }

            // override existing alaomReq (updating token in header)
            var request: AlamofireRequestModal = alaomReq
            request.headers = ["Content-Type": "application/json",
                               "X-Requested-With": "XMLHttpRequest",
                               "Cache-Control": "no-cache",
                               "X-Authorization": self.getAccessToken()]

            self.callWebServiceAlamofire(request, success: success, failure: failure)

        }, failure: { (_) in
            self.requestForGetNewAccessToken(alaomReq: alaomReq, success: success, failure: failure)
        })
    }

}

为了从此调用调用 API,我们需要创建一个 AlamofireRequestModal 对象并用必要的参数覆盖它.

For calling the API from this call, we need to create a object of AlamofireRequestModal and override it with necessary parameter.

例如,我创建了一个文件 APIService.swift,其中我们有一个用于 getUserProfileData 的方法.

For example I created a file APIService.swift in which we have a method for getUserProfileData.

APIService.swift :

import Foundation

let GET_USER_PROFILE_METHOD = "user/profile"

struct BaseURL {
    // Local Server
    static let urlString: String = "http://192.168.10.236: 8084/"
    // QAT Server
    // static let urlString: String = "http://192.171.286.74: 8080/"

    static let staging: String = BaseURL.urlString + "api/v1/"
}

class APIService: BaseService {

    func getUserProfile(success: @escaping ((_ responseObject: AnyObject?) -> Void), failure: @escaping ((_ error: NSError?) -> Void)) {

        var request: AlamofireRequestModal = AlamofireRequestModal()
        request.method = .get
        request.path = BaseURL.staging + GET_USER_PROFILE_METHOD
        request.headers = ["Content-Type": "application/json",
                           "X-Requested-With": "XMLHttpRequest",
                           "Cache-Control": "no-cache",
                           "X-Authorization": getAccessToken()]

        self.callWebServiceAlamofire(request, success: success, failure: failure)
    }

}

说明:

在代码块中:

else if statusCode == 403 {
    // Access token expire
    self.requestForGetNewAccessToken(alaomReq: alamoReq, success: success, failure: failure)
}

我调用 getNewAccessToken API(在您的情况下是刷新令牌),请求(它可以是基于 APIService.swift 的任何请求).

I call getNewAccessToken API (say refresh-token, in your case), with the request( it could be any request based from APIService.swift).

当我们获得新令牌时,我将其保存为用户默认值,然后我将更新请求(我在刷新令牌 API 调用中作为参数获取的请求),并将按原样传递成功和失败块.

When we get new token I save it user-defaults then I will update the request( the one I am getting as a parameter in refresh-token API call), and will pass the success and failure block as it is.

这篇关于刷新令牌的正确方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆