Last active
May 19, 2017 13:04
-
-
Save Akhu/425452dfe11f32cae5b6f731e0cb9a14 to your computer and use it in GitHub Desktop.
Sample on how to manage authentication of an oauth api with alamofire and swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Authentication.swift | |
// | |
// Created by Anthony on 04/05/2017. | |
// Copyright © 2017 Aboutgoods. All rights reserved. | |
// | |
import Foundation | |
import Alamofire | |
class Authentication: RequestAdapter, RequestRetrier { | |
private typealias RefreshCompletion = (_ succeeded: Bool, _ 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 baseURLString: String = Router.baseURLString | |
private var refreshToken: String | |
private var isRefreshing = false | |
private var requestsToRetry: [RequestRetryCompletion] = [] | |
// MARK: - Initialization | |
public init(refreshToken: String){ | |
self.refreshToken = refreshToken | |
} | |
// MARK: - RequestAdapter | |
func adapt(_ urlRequest: URLRequest) throws -> URLRequest { | |
if let urlString = urlRequest.url?.absoluteString, urlString.hasPrefix(self.baseURLString) { | |
var urlRequestToSend = urlRequest | |
urlRequestToSend.setValue(refreshToken, forHTTPHeaderField: "token_header") | |
} | |
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 { | |
self.refreshTokens { [weak self] succeeded, refreshToken in | |
guard let strongSelf = self else { return } | |
strongSelf.lock.lock() ; defer { strongSelf.lock.unlock() } | |
if let refreshToken = refreshToken { | |
strongSelf.refreshToken = refreshToken | |
} | |
strongSelf.requestsToRetry.forEach { $0(succeeded, 0.0) } | |
strongSelf.requestsToRetry.removeAll() | |
} | |
} | |
} | |
} | |
private func refreshTokens(completion: @escaping RefreshCompletion){ | |
guard !isRefreshing else { return } | |
isRefreshing = true | |
if Core.uuid != nil { //When user is already known | |
sessionManager.request(Router.login).responseJSON { [weak self] response in | |
guard let strongSelf = self else { return } | |
if | |
let json = response.result.value as? [String:Any], | |
let token = json["token"] as? String, | |
{ | |
Core.uuid = uuid | |
completion(true, token) | |
}else { | |
completion(false, nil) | |
} | |
strongSelf.isRefreshing = false | |
} | |
}else { //If no UUID, its the first time that we see this user, we need to request new uuid | |
sessionManager.request(Router.requestUUID).responseJSON { [weak self] response in | |
guard let strongSelf = self else { return } | |
if | |
let json = response.result.value as? [String:Any], | |
let token = json["token"] as? String, | |
{ | |
Core.uuid = uuid | |
completion(true, token) | |
}else{ | |
completion(false, nil) | |
} | |
strongSelf.isRefreshing = false | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment