我使用 AsWebAuthenticationsession 从另一个应用程序到我的应用程序进行身份验证。我打开 AsWebAuthenticationsession,它会重定向我的应用程序的通用链接。问题是当它重定向我的应用程序通用链接时,它要求打开应用程序商店。当它重定向时我想关闭会话。但 AsWebAuthenticationsession 只采用自定义 URL 方案。我怎样才能安全地处理它(因为自定义 URL 方案不安全:RFC8252 7.1)
我可以确认这在 iOS 14 或更高版本中有效,但尚未在早期版本上进行测试。
初始化
ASWebAuthenticationSession
时,可以传入callbackURLScheme: "https"
。
当身份验证提供程序重定向到您的通用链接时,您的应用程序委托的
application(_:continue:restorationHandler:)
将使用正确的重定向 URL 触发,但是 ASWebAuthenticationSession
的完成处理程序不会 触发,因此身份验证对话框仍保留在屏幕上.
您需要手动保存对
ASWebAuthenticationSession
和 cancel()
的引用才能将其关闭。
你可以尝试一下这个方法
添加一个单例类来处理此回调
SceneDelegate.swift
@available(iOS 13.0, *)
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
// handle here
OAuthManager.instance.callBackUserActivity(userActivity: userActivity)
}
OAuthManager.swift
import Foundation
import AuthenticationServices
protocol UserActivityListener {
func callBackUserActivity( userActivity : NSUserActivity )
}
class OAuthManager {
public static let instance = OAuthManager()
var asWebSession: ASWebAuthenticationSession?
}
extension OAuthManager : UserActivityListener {
func callBackUserActivity(userActivity: NSUserActivity) {
// Get URL components from the incoming user activity.
guard userActivity.activityType == NSUserActivityTypeBrowsingWeb,
let incomingURL = userActivity.webpageURL,
let components = NSURLComponents(url: incomingURL, resolvingAgainstBaseURL: true) else {
return
}
// Check for specific URL components that you need.
guard let path = components.path,
let params = components.queryItems else {
return
}
// cancel your ASWebAuthenticationSession
asWebSession?.cancel()
print("path = \(userActivity.webpageURL)")
if let token = params.first(where: { $0.name == "token" })?.value {
print("token = \(token)")
}
}
}
你的ViewController.swift
class YourViewController: UIViewController {
// set your instance
var oauthManager = OAuthManager.instance
private func startSignInAsWebAuthSession() {
let callbackURLScheme = "YOURAPP"
guard let authURL = URL(string: "YOUR URL LINK") else { return }
self.oauthManager.asWebSession = ASWebAuthenticationSession.init(url: authURL, callbackURLScheme: callbackURLScheme,completionHandler: { callbackURL, error in
// we dont listen to the call back, this web authentication session only open for login only
})
oauthManager.asWebSession?.prefersEphemeralWebBrowserSession = true
oauthManager.asWebSession?.presentationContextProvider = self
oauthManager.asWebSession?.start()
}
}
extension YourViewController: ASWebAuthenticationPresentationContextProviding {
func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor {
ASPresentationAnchor()
}
}
今天(2024 年)我使其工作的唯一方法(特别是使用 SwiftUI)是在 AWS 上创建 lambda 无服务器服务,我使用路径
auth\appLogin
注册了重定向 URL,在我的例子中,该路径处理来自 OAuth 2.0 的响应响应类型是 code
,所以我需要调用另一个 API 来获取 accesss_token
,然后以重定向作为在我的应用程序上注册的 URL 方案进行响应:
resolve({
statusCode: 302,
headers: {
'Location': `myapp://callback?access_token=${JSON.parse(body).access_token}`
}
});
这是我的 SwiftUI 代码
if let authURL = URL(string: "\(baseURL)?response_type=\(responseType)&client_id=\(clientId)&redirect_uri=\(redirectUrl)&scope=\(scopesString)") {
let scheme = "myapp" // Your app's custom URL scheme
let session = ASWebAuthenticationSession(url: authURL, callbackURLScheme: scheme) { callbackURL, error in
guard error == nil, let callbackURL = callbackURL else {
print("Authorization failed: \(String(describing: error))")
return
}
// Handle the authorization code from the callbackURL
let queryItems = URLComponents(string: callbackURL.absoluteString)?.queryItems
if let access_token = queryItems?.first(where: { $0.name == "access_token" })?.value {
print("Authorization token: \(access_token)")
}
}
session.presentationContextProvider = contextProvider
session.start()
}
还记得注册您的 URL 方案 :