web-dev-qa-db-fra.com

Swift: Comment se souvenir des cookies pour les requêtes http suivantes

Je travaille sur une application de connexion. Après la connexion réussie, la réponse revient avec les données du cookie.
Comment puis-je utiliser/sauvegarder ces données pour mes futures demandes?
Pour commencer, j'essaie de le sauvegarder dans NSHTTPCookieStorage. Mais cela ne fonctionne pas non plus .
Méthode de connexion (partielle):

let task = session.dataTaskWithRequest(request) { (data, responseData, error) -> Void in
            if let response = responseData as? NSHTTPURLResponse {
                statusCode = response.statusCode
                print("Response code: \(statusCode)")
            }

            var json: NSDictionary?
            do {
                json = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableLeaves) as? NSDictionary
            } catch {
                print(error)
                err = error
            }

            if(statusCode != 200) {

                let jsonStr = NSString(data: data!, encoding: NSUTF8StringEncoding)
                print("Error could not parse JSON: '\(jsonStr)'")
            }
            else {

                print("Everything Looks good: \(responseData)")
                self.setCookies(responseData!)
                self.shouldPerformSegueWithIdentifier("showHomeController", sender: self)

            }
        }

        task?.resume()

Enregistrer la méthode du cookie

private func setCookies(response: NSURLResponse) {
        if let httpResponse = response as? NSHTTPURLResponse {
            let cookies = NSHTTPCookie.cookiesWithResponseHeaderFields(httpResponse.allHeaderFields, forURL: response.URL!) as! [NSHTTPCookie]
            NSHTTPCookieStorage.sharedHTTPCookieStorage().setCookies(cookies, forURL: response.URL!, mainDocumentURL: nil)
            for cookie in cookies {
                var cookieProperties = [String: AnyObject]()
                cookieProperties[NSHTTPCookieName] = cookie.name
                cookieProperties[NSHTTPCookieValue] = cookie.value()
                cookieProperties[NSHTTPCookieDomain] = cookie.domain
                cookieProperties[NSHTTPCookiePath] = cookie.path
                cookieProperties[NSHTTPCookieVersion] = NSNumber(integer: cookie.version)
                cookieProperties[NSHTTPCookieExpires] = NSDate().dateByAddingTimeInterval(31536000)

                let newCookie = NSHTTPCookie(properties: cookieProperties)
                NSHTTPCookieStorage.sharedHTTPCookieStorage().setCookie(newCookie!)

                println("name: \(cookie.name) value: \(cookie.value())")
            }
        }
    }

Erreur:

Cannot invoke 'cookiesWithResponseHeaderFields' with an argument list of type '([NSObject : AnyObject], forURL: NSURL)'
16
Himanshu Yadav

Si vous vous rendez compte de l'utilisation du cookie, le serveur doit envoyer l'en-tête Set-Cookie en réponse à la demande du client. Inspectez simplement l'en-tête en réponse et vous verrez le champ d'en-tête Set-Cookie avec le cookie.

_ { https://en.wikipedia.org/wiki/HTTP_cookie#Setting_a_cookie } _

Si vous utilisez URLSession avec la variable par défaut ou l'arrière-plan URLSessionConfiguration, vous ne devez apporter aucune modification pour enregistrer le cookie. Si vous regardez la documentation par défaut URLSessionConfiguration, qui la décrit comme ceci,

La configuration de session par défaut utilise un cache persistant basé sur disque (sauf lorsque le résultat est téléchargé dans un fichier) et stocke informations d’identité dans le trousseau de l’utilisateur. Il stocke également les cookies (par Default) dans le même magasin de cookies partagé que NSURLConnection et NSURLDownload classes.

Vous pouvez également en savoir plus à ce sujet dans la documentation URLSessionConfiguration de la propriété httpCookieStorageici .

Voici un petit extrait de code que je vais utiliser plus tard pour tester le stockage des cookies.

let sessionConfiguration = URLSessionConfiguration.ephemeral
sessionConfiguration.httpCookieAcceptPolicy = .never
let customSession = URLSession(configuration: sessionConfiguration)

enum Result {
    case success(HTTPURLResponse, Data)
    case failure(Error)
}

func readCookie(forURL url: URL) -> [HTTPCookie] {
    let cookieStorage = HTTPCookieStorage.shared
    let cookies = cookieStorage.cookies(for: url) ?? []
    return cookies
}

func deleteCookies(forURL url: URL) {
    let cookieStorage = HTTPCookieStorage.shared

    for cookie in readCookie(forURL: url) {
        cookieStorage.deleteCookie(cookie)
    }
}

func storeCookies(_ cookies: [HTTPCookie], forURL url: URL) {
    let cookieStorage = HTTPCookieStorage.shared
    cookieStorage.setCookies(cookies,
                             for: url,
                             mainDocumentURL: nil)
}


func executeURLRequest(url: URL, inSession session: URLSession = .shared, completion: @escaping (Result) -> Void) {
    let task = session.dataTask(with: url) { data, response, error in

        if let response = response as? HTTPURLResponse,
            let data = data {
            completion(.success(response, data))
            return
        }

        if let error = error {
            completion(.failure(error))
            return
        }

        let error = NSError(domain: "com.cookiesetting.test", code: 101, userInfo: [NSLocalizedDescriptionKey: "Unknown error occurred"])
        completion(.failure(error))
    }
    task.resume()
}

Avec l'extrait de code ci-dessus, nous testons d'abord que la session par défaut enregistre le cookie.

var cookies = readCookie(forURL: googleURL)
print("Cookies before request: ", cookies)

executeURLRequest(url: googleURL) { result in
    if case .success (let data) = result {
        cookies = readCookie(forURL: googleURL)
        print("Cookies after request: ", cookies)

        deleteCookies(forURL: googleURL)
        cookies = readCookie(forURL: googleURL)
        print("Cookies after deletion: ", cookies)
    }
}

Et voici ce que nous obtenons,

Cookies before request:  []
Cookies after request:  [<NSHTTPCookie
    version:0
    name:1P_JAR
    value:2018-09-26-15
    expiresDate:'2018-10-26 15:39:46 +0000'
    created:'2018-09-26 15:39:46 +0000'
    sessionOnly:FALSE
    domain:.google.com
    partition:none
    sameSite:none
    path:/
    isSecure:FALSE
 path:"/" isSecure:FALSE>, <NSHTTPCookie
    version:0
    name:NID
    value:139=E3g4bKNRGcYoeFuaECpfsx_Efp64xONmVwcJS7f7PuZe8LayS5ZkGuz3f7z6eq7zoBm2z-opTvzX8YPzn8v1ebjH6iyt5-6yDYm9RE6XhXwHCZWs98_j7nb11u2EPnHI
    expiresDate:'2019-03-28 15:39:46 +0000'
    created:'2018-09-26 15:39:46 +0000'
    sessionOnly:FALSE
    domain:.google.com
    partition:none
    sameSite:none
    path:/
    isSecure:FALSE
    isHTTPOnly: YES
 path:"/" isSecure:FALSE isHTTPOnly: YES>]
Cookies after deletion:  []

URLSessionConfiguration a également une propriété httpCookieAcceptPolicy, qui cite ce qui suit:

Cette propriété détermine la politique d'acceptation des cookies pour toutes les tâches de sessions basées sur cette configuration.

La valeur par défaut est HTTPCookie.AcceptPolicy.onlyFromMainDocumentDomain. Vous pouvez le changer à l'une des constantes définies dans HTTPCookie.AcceptPolicy type énuméré.

Si vous souhaitez davantage de contrôle direct sur les cookies acceptés, définissez cette valeur à HTTPCookie.AcceptPolicy.never, puis utilisez le fichier allHeaderFields et les cookies (withResponseHeaderFields: for :) méthodes to extraire les cookies de l'objet de réponse URL vous-même.

Ainsi, si vous souhaitez manipuler le cookie vous-même, vous pouvez définir la variable httpCookieAcceptPolicy sur never.

Le code suivant montre, cookie non enregistré lors de l'utilisation de httpCookieAcceptPolicy to never,

var cookies = readCookie(forURL: googleURL)
print("Cookies before request: ", cookies)

executeURLRequest(url: googleURL, inSession: customSession) { result in
    if case .success (let data) = result {
        cookies = readCookie(forURL: googleURL)
        print("Cookies after request: ", cookies)

    }
}

Qui enregistre les suivants:

Cookies before request:  []
Cookies after request:  []

Vous pouvez constater qu'en utilisant .never pour httpCookieStoragePolicy, le système ne stocke pas de cookie dans un stockage de cookie partagé. 

Vous pouvez également stocker le cookie vous-même, qui ressemblerait à ceci,

Stocker le cookie par nous-mêmes

deleteCookies(forURL: googleURL)
var cookies = readCookie(forURL: googleURL)
print("Cookies before request: ", cookies)
executeURLRequest(url: googleURL, inSession: customSession) { result in
    if  case let .success  (response, data) = result {
        guard let cookiesResponseHeader = response.allHeaderFields["Set-Cookie"] else {
            return
        }

        cookies = readCookie(forURL: googleURL)
        print("Cookies after request: ", cookies)

        let responseCookies = HTTPCookie.cookies(withResponseHeaderFields: response.allHeaderFields as! [String: String], for: googleURL)
        storeCookies(responseCookies, forURL: googleURL)
        cookies = readCookie(forURL: googleURL)
        print("Cookies after storing: ", cookies)

    }
}

Et, voici ce que le code ci-dessus affiche sur la console,

Cookies before request:  []
Cookies after request:  []
Cookies after storing:  [<NSHTTPCookie
    version:0
    name:1P_JAR
    value:2018-09-26-18
    expiresDate:'2018-10-26 18:35:23 +0000'
    created:'2018-09-26 18:35:23 +0000'
    sessionOnly:FALSE
    domain:.google.com
    partition:none
    sameSite:none
    path:/
    isSecure:FALSE
 path:"/" isSecure:FALSE>, <NSHTTPCookie
    version:0
    name:NID
    value:139=D7GTUazWfeaB5Bcu1wN5I_Il2k6xALNiRZDX_DN9totQbnrP31gE0GzlsjCHDISUv8ulPq9G8Yu1p-GsZcVRw2fnrBROih-vtAVBic5UXFKUkG_ZbFQYKFprr4MPHDGS
    expiresDate:'2019-03-28 18:35:23 +0000'
    created:'2018-09-26 18:35:23 +0000'
    sessionOnly:FALSE
    domain:.google.com
    partition:none
    sameSite:none
    path:/
    isSecure:FALSE
    isHTTPOnly: YES
 path:"/" isSecure:FALSE isHTTPOnly: YES>]

Le code ci-dessus utilise .never HTTPCookieAcceptPolicy pour URLSessionConfiguration mais nous créons un cookie à partir de la réponse et le stockons nous-mêmes dans le magasin de cookies. 

23
Sandeep

class func cookiesWithResponseHeaderFields (_ headerFields: [String: String], URL forURL: NSURL) -> [NSHTTPCookie]

Notez que headerFields est [String: String] Dictionary et que le compilateur se plaint de passer [NSObject: AnyObject].

1
Edward Ashak