Swift 3.0令牌到期将如何自动调用令牌?

时间:2017-09-04 06:05:20

标签: ios swift token access-token

收到令牌后,当令牌结束时,如何在登录后自动调用令牌?在同一页上

 Alamofire.request(urlString, method: .post, parameters: newPost, encoding: JSONEncoding.default)
        .responseJSON { response in

            if let json = response.result.value as? [String : Any]{
                print("JSON: \(json)")
                if UserDefaults.standard.bool(forKey: "logged_in") {

                    Token = json["Token"]! as! String

                    UserDefaults.standard.set(Token, forKey: "Token")
                    UserDefaults.standard.synchronize()

                }

            } else {
                print("Did not receive json")
            }

            //expectation.fulfill()
    }

4 个答案:

答案 0 :(得分:6)

对于Authorisation Token,理想的做法是从服务器端进行检查,请求的API调用TOKEN是否有效。如果令牌未匹配或已过期,则会提供HTTP status code 401,您需要先从移动端检查状态代码,如果找到401,则需要强制注销或重新登录需要一个新令牌,您可以将其保存在UserDefaults

答案 1 :(得分:3)

场景1:您需要告诉后台开发人员谁做了您的网络服务,他需要检查TOKEN是否有效。如果令牌过期,他需要提供消息代码或消息“令牌已过期"并且您可以在“响应”中检查消息代码是否已过期,而不是导航“登录”屏幕。 这是最佳做法。

场景2:如果您不想从应用退出,并让应用程序继续使用新令牌自动刷新,请告诉webservice开发人员,无论何时令牌过期,他都会在响应字段中返回新令牌"授权"从代码方面来说,您需要检查每个请求是否授权包含新令牌。如果它包含,则表示您需要在userdefault中将旧令牌替换为新令牌。

以下是我在Swift3中的代码:

func requestApiCall(_ urlString: String, paramData: NSObject, completionHandler: @escaping (NSDictionary?, NSError?) -> ()) {

    let token =   UserDefaults.standard.object(forKey: “token” as String)
    var headersVal = [
        "Authorization": "Bearer "+(token as String),
    ]

 Alamofire.request(urlString, method: .post, parameters: paramData as? [String : AnyObject],encoding: JSONEncoding.default, headers: headersVal)

        .responseJSON { response in

            if let authorization = response.response?.allHeaderFields["Authorization"] as? String {

                var newToken : String = authorization
                UserDefaults.standard.set(newToken, forKey: "token")
                UserDefaults.standard.synchronize()
            }

            switch response.result {

            case .success(let value):

              if let res = response.result.value {
                     let response = res as! NSDictionary
                     let message = response.object(forKey: "message”)!
                     print(message)
                if message as! String ==  "Token has been expired" 
                {
                    self.showLoginScreen()
                }
              }
            completionHandler(value as? NSDictionary, nil)

            case .failure(let error):
                if error._code == -1001 {
                    print("timeout")
                }
                completionHandler(nil, nil)
            }
      }
}

答案 2 :(得分:0)

在令牌过期时为新令牌调用服务对您的应用程序不安全,因为如果令牌过期并且您为新令牌调用服务,则任何人都可以访问您的应用或其数据。更好的方法是注销/退出用户并要求他再次登录。

但是如果你想这样做,那么创建一个用户获取新令牌的方法,并在获得令牌过期代码后调用它。

但你需要与你的后端开发人员讨论这个新api,因此你可以进一步移动

让我知道帮助。谢谢

答案 3 :(得分:0)

我更喜欢使用Moya框架(Alamofire下的抽象)和PromiseKit。它可以更轻松地编写异步代码并在部件之间创建依赖关系。我包装了所有业务逻辑,用于在类中发送请求。请求的主要功能(public func register(device: String, type: String) -> Promise<Device>)返回Promise个对象。在recover块中,我验证了错误代码,如果需要,我刷新令牌并重复失败的请求。代码示例如下:

public protocol HttpClientInterface {
...
    func register(device: String, type: String) -> Promise<Device>
...
}

public func register(device: String, type: String) -> Promise<Device> {
    return self.sendRegisterRequest(with: device, type: type)
        .then {
            self.parseRegister(response: $0)
        }
        .recover { lerror -> Promise<Device> in
            guard let error = lerror as? HttpClientError,
                case .server(let value) = error,
                value == ServerError.notAuthenticated,
                let refreshToken = self.credentialsStore.get()?.token?.refreshToken else {
                    throw lerror
            }

            return self.sendRefreshSessionRequest(operatorId: self.operatorId, refreshToken: refreshToken)
                .then { data -> Promise<AuthToken> in
                    return self.parseRefreshSession(data)
                }
                .then { token -> Promise<Device> in
                    self.credentialsStore.update(token: token)
                    return self.register(device: device, type: type)
                }
                .catch { error in
                    if let myError = error as? HttpClientError,
                        case .server(let value) = httpError,
                        value == ServerError.notAuthenticated {
                        self.credentialsStore.accessDenied()
                    }
            }
    }
}

func sendRegisterRequest(with name: String, type: String) -> Promise<Data> {
    return Promise { fulfill, reject in
        self.client.request(.register(device: name, type: type)) {
            self.obtain(result: $0,
                        successStatusCodes: [200, 201],
                        fulfill: fulfill,
                        reject: reject)
        }
    }
}

func parseRegister(response data: Data) -> Promise<Device> {
    return Promise { fulfill, reject in
        if let account = Account(data: data),
            let device = account.devices?.last {
            fulfill(device)
        } else {
            reject(HttpClientError.internalError())
        }
    }
}