Swift 4 WKWebView Аутентификация из цепочки для ключей - PullRequest
0 голосов
/ 27 августа 2018

У меня очень простая веб-страница, использующая CakePHP 3.x, и я написал простое приложение Swift 4 для отображения этого сайта. Пока приложение остается открытым, сеансы будут продолжать работать. Как только приложение закрыто, пользователь должен снова войти в систему. Я считаю, что это правильное поведение, потому что сеансовые куки хранятся в памяти и удаляются после закрытия браузера, но исправьте меня, если я ошибаюсь. Мои пользователи хотят войти в систему один раз и просто автоматически входить в систему каждый раз, когда снова открывают приложение.

Я использую Swift 4 и WKWebView. Есть ли способ сохранить учетные данные пользователя в цепочке для ключей для определенного URL, когда пользователь отправляет форму входа? Я обнаружил, что могу использовать Javascript для манипулирования полями формы, используя WKWebView здесь , но это использует swift 2 или 1Password. Я также нашел этот пост , показывающий, как использовать цепочку для ключей для хранения учетных данных. Вид искать комбинацию двух. Мне также нужно знать, какие списки мне нужно включить, чтобы это работало.

Шаги, которые я пытаюсь выполнить:

  1. Пользователь открывает приложение в первый раз, и когда WKWebView переходит на основной URL, GET "/".

  2. CakePHP видит, что пользователь не авторизован, и перенаправляет на страницу входа в систему, GET "/users/login".

  3. На данный момент я хотел бы проверить цепочку для ключей на наличие учетных данных, связанных с этим URL, но поскольку пользователи впервые открывают приложение, учетные данные не должны существовать. Пользователь входит в систему и нажимает кнопку отправить, POST "/users/login".

  4. Перед публикацией формы запросите разрешение на хранение учетных данных в связке ключей.

  5. Пользователь закрывает приложение, очищая сеанс.

  6. Пользователь открывает приложение, шаги 1 и 2 повторяются, но на этот раз учетные данные шага 3 существуют. На этом этапе я хотел бы загрузить учетные данные из цепочки для ключей, заполнить поля имени пользователя и пароля, а затем активировать отправку.

Вот копия моего контроллера вида:

import UIKit
import WebKit

class ViewController: UIViewController, WKNavigationDelegate {
    var webView: WKWebView!

    override func viewDidLoad() {
        super.viewDidLoad()
        let url = URL(string: "https://www.example.com")!
        webView.load(URLRequest(url:url))
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    override func loadView() {
        webView = WKWebView()
        webView.navigationDelegate = self
        view = webView
    }

    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation) {
        title = webView.title
    }
}

РЕДАКТИРОВАТЬ 1: Как предлагается в комментариях, я добавил функцию аутентификации на основе токенов, проверив заголовок запроса и установив сеанс, если токен существует. Когда пользователь регистрируется в первый раз, токен генерируется и отправляется обратно в ответ. Я добавил еще одну функцию webView в свой ViewController для поиска токена в заголовке ответа.

func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
    let token = (navigationResponse.response as! HTTPURLResponse).allHeaderFields["X-SAMPLE-TOKEN-HEADER"] as? String
    print(token)
    decisionHandler(.allow)
} 

РЕДАКТИРОВАТЬ 2: Оказывается, добавить заголовок к объекту URLRequest не так сложно в Swift. Я обновил свой viewDidLoad (), чтобы добавить заголовок токена, прежде чем webView загрузит запрос. Я изменил URL, чтобы перейти прямо на страницу входа. Я проверил это, и мой пользователь авторизован, и его сеанс установлен, когда присутствует заголовок.

override func viewDidLoad() {
    super.viewDidLoad()      
    var request = URLRequest(url:URL(string: "https://www.example.com/users/login")!)
    request.addValue("abcdef01234567890fedcba9871634556211", forHTTPHeaderField: "X-SAMPLE-TOKEN-HEADER")
    webView.load(request)
}

РЕДАКТИРОВАТЬ 3: Используя этот stackoverflow answer , я обновил свой ViewController для хранения токена, если он найден в ответе, и для добавления токена в заголовок до того, как webView загрузит URLRequest .

let key = "com.example.www.token"
let header = "X-SAMPLE-TOKEN-HEADER"

override func viewDidLoad() {
    super.viewDidLoad()
    var request = URLRequest(url:URL(string: "https://www.example.com/users/login")!)
    let token = UserDefaults.standard.string(forKey: key)

    if (token != nil) {
        request.addValue(token!, forHTTPHeaderField: header)
    }

    webView.load(request)
}

func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {

    let token = (navigationResponse.response as! HTTPURLResponse).allHeaderFields[header] as? String

    if (token != nil) {
        if (UserDefaults.standard.string(forKey: key) != nil) {
            UserDefaults.standard.removeObject(forKey: key)
        }

        UserDefaults.standard.set(token, forKey: key)
    }

    decisionHandler(.allow)
}

Я открыт для предложений о том, как сделать это лучше, но пока он оправдывает ожидания.

1 Ответ

0 голосов
/ 31 августа 2018

Используя аутентификацию на основе токенов, как было предложено, токены генерируются и передаются обратно в заголовок ответа при входе пользователя в систему.

WKNavigationDelegate имеет метод , передающий объект WKNavigationResponse, который позволяет просматривать ответ, включая заголовки.

func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
    ... do stuff

    let headerValue = (navigationResponse.response as! HTTPURLResponse).allHeaderFields["X-HEADER-NAME"] as? String

    ... do more stuff
}

Класс UserDefaults может использоваться для хранения, извлечения или удаления токена.

let tokenKey = "unique.identifier"
let newToken = "NEWTOKEN12345"
let oldToken = UserDefaults.standard.string(forKey: tokenKey)

if (oldToken != nil) {
    UserDefaults.standard.removeObject(forKey: tokenKey)
}

UserDefaults.standard.set(token, forKey: tokenKey)

Чтобы добавить заголовок только к вашему первоначальному запросу, вы можете изменить объект URLRequest, добавив заголовок до того, как webView загрузит его.

override func viewDidLoad() {
    ... do stuff

    let tokenKey = "unique.identifier"
    let token = UserDefaults.standard.string(forKey: tokenKey)

    var request = URLRequest(url:URL(string: "https://www.example.com/users/login")!)

    if (token != nil) {
        request.addValue(token!, forHTTPHeaderField: header)
    }

    ... do more stuff

    webView.load(request)
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...