У меня очень простая веб-страница, использующая CakePHP 3.x, и я написал простое приложение Swift 4 для отображения этого сайта. Пока приложение остается открытым, сеансы будут продолжать работать. Как только приложение закрыто, пользователь должен снова войти в систему. Я считаю, что это правильное поведение, потому что сеансовые куки хранятся в памяти и удаляются после закрытия браузера, но исправьте меня, если я ошибаюсь. Мои пользователи хотят войти в систему один раз и просто автоматически входить в систему каждый раз, когда снова открывают приложение.
Я использую Swift 4 и WKWebView. Есть ли способ сохранить учетные данные пользователя в цепочке для ключей для определенного URL, когда пользователь отправляет форму входа? Я обнаружил, что могу использовать Javascript для манипулирования полями формы, используя WKWebView здесь , но это использует swift 2 или 1Password. Я также нашел этот пост , показывающий, как использовать цепочку для ключей для хранения учетных данных. Вид искать комбинацию двух. Мне также нужно знать, какие списки мне нужно включить, чтобы это работало.
Шаги, которые я пытаюсь выполнить:
Пользователь открывает приложение в первый раз, и когда WKWebView переходит на основной URL, GET "/".
CakePHP видит, что пользователь не авторизован, и перенаправляет на страницу входа в систему, GET "/users/login".
На данный момент я хотел бы проверить цепочку для ключей на наличие учетных данных, связанных с этим URL, но поскольку пользователи впервые открывают приложение, учетные данные не должны существовать. Пользователь входит в систему и нажимает кнопку отправить, POST "/users/login".
Перед публикацией формы запросите разрешение на хранение учетных данных в связке ключей.
Пользователь закрывает приложение, очищая сеанс.
Пользователь открывает приложение, шаги 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)
}
Я открыт для предложений о том, как сделать это лучше, но пока он оправдывает ожидания.