SFAuthenticationSession 如何在 Safari 中存储会话相关的 cookie

How does SFAuthenticationSession store session related cookies in Safari

tl;博士 阅读最后一段。

我正在使用 AppAuth (https://github.com/openid/AppAuth-iOS) 库来处理基于 OpenID 的用户身份验证,我想通过我的应用程序为其提供 SSO 体验。我的应用程序的部署目标是 iOS 11,这意味着 AppAuth 内部使用 SFAuthenticationSession。我正在使用授权流程,这意味着通过 SFAuthenticationSession 向用户显示基于 Web 的登录页面。当用户填写并提交凭据时,SFAuthenticationSession 调用完成 url(如果成功),从中可以解析授权 code。通过授权 code 通过 URLSession 的令牌 POST 请求独立于 SFAuthenticationSession 并检索 access_token

包括 access_token 的检索在内的整个流程都是成功的,但是当我离开应用程序并在 Safari 中打开服务提供商提供的用户个人资料网页时,用户没有登录。我测试了相同的使用 Google 帐户(https://accounts.google.com) and SSO worked fine, e.g. when I opened https://mail.google.com 在 Safari 中登录。所以我怀疑我的服务提供商做错了什么。也许他们没有为我提供正确的范围?但在联系他们之前我想排除我的任何错误。现在我最直接的想法是,以某种方式与会话相关的 cookie 没有存储在 Safari 中。由此我的问题如下。

我的问题。令牌 POST 请求是独立于 SFAuthenticationSession(不同的用户代理)发出的,那么如果不通过 SFAuthenticationSession,任何与会话相关的 cookie 如何存储在设备(Safari)上?有没有什么方法可以在代码中调试 cookie 存储?

要调试 cookie,您可以使用此代码:

import UIKit

import WebKit

class ViewController: UIViewController, WKNavigationDelegate {

var webView: WKWebView?

override func viewDidLoad() {
    super.viewDidLoad()

    let configuration = WKWebViewConfiguration()
    webView = WKWebView(frame: .zero,configuration:configuration)
    self.view = webView
}

override func viewDidAppear(_ animated: Bool) {
    let url = URL(string: "YOUR URL")

    let request = URLRequest(url: url!)

    webView?.navigationDelegate = self
    webView?.addObserver(self, forKeyPath: "URL", options: [.new, .old], context: nil)

    self.webView?.load(request)
}

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {

    if let newValue = change?[.newKey] as? Int, let oldValue = change?[.oldKey] as? Int, newValue != oldValue {

        print("NEW",change?[.newKey])
    } else {
        print("OLD",change?[.oldKey])

    }

    webView?.configuration.websiteDataStore.httpCookieStore.getAllCookies { cookies in
        for cookie in cookies {
            print(cookie)
        }
    }
}
}

并检查 cookie 是否有 expiresDate 属性。否则您将无法使用 SSO。

根据 OAuth 2.0 标准,token endpoint does not require the resource owner authentication, as an opposite to the authorization endpoint 确实如此。 (执行授权代码交换的脚本或后台通道不一定能够访问用户代理中设置的 HTTP cookie,并且默认情况下,浏览器不会在跨站点 XHR 中包含凭据。使用刷新令牌时,资源所有者根本不需要交互。)您的 URLSession 没有从 Safari 或 SFAuthenticationSession 获取任何会话 cookie,因此不需要。

至于您的移动 Safari 体验,ASWebAuthenticationSession 的文档,SFAuthenticationSession 继任者,声明:

All cookies, except session cookies, can be shared with Safari.

SFAuthenticationSession 似乎也是如此。 Google 必须使用持久性 cookie,因此会话共享适用于它们。

附带说明,即使使用持久性 cookie,在 iOS 11 环境中同步 cookie jar 似乎也存在一些不一致,例如:http://www.openradar.me/radar?id=5036182937272320

如果您不想在浏览器中存储 cookie,您可以通过私人浏览会话进行身份验证,其中 ASWebAuthenticationSession 并将 prefersEphemeralWebBrowserSession 设置为 true。

https://github.com/openid/AppAuth-iOS/issues/530#issuecomment-628159766