适用于 Swift(iOS/macOS)的 OAuth 客户端库
OAuth(开放授权)是一种开放的授权协议,允许应用程序在不传递用户登录名和密码的情况下,获取对用户资源的有限访问权限。在 Apple 生态系统(iOS、macOS、watchOS、tvOS)中,实现 OAuth 2.0 是与 Google、Facebook、GitHub、Twitter 等服务集成的标准。对于 Swift 开发者来说,有多个经过验证的库可以简化身份验证和令牌管理过程。
在本文中,我们将介绍最流行且灵活的库之一——OAuthSwift,并讨论其替代方案——AppAuth-iOS(Google 推荐)。您将了解如何集成该库、执行授权、获取访问令牌、刷新令牌并安全地存储它们。
OAuthSwift 的主要功能
- 支持 OAuth 1.0 和 OAuth 2.0
- 内置 WebView 支持(SFSafariViewController、WKWebView)
- 自动获取和更新访问令牌
- 支持多种授权类型(授权码、隐式、客户端凭证、资源所有者密码)
- 与 Alamofire、URLSession 和其他网络框架轻松集成
- 异步回调(完成处理程序)并支持 Combine(通过扩展)
- 通过 Keychain 安全存储令牌
安装 OAuthSwift
该库可通过 Swift Package Manager(SPM)或 CocoaPods 安装。SPM 示例:
// 在 Xcode 中:File → Add Packages...// URL:https://github.com/OAuthSwift/OAuthSwift.git// 版本:2.2.0 及以上或者通过 Package.swift:
dependencies: [ .package(url: "https://github.com/OAuthSwift/OAuthSwift.git", from: "2.2.0")]与 OAuth 2.0(Google)集成的示例
考虑一个典型场景——通过 Google 授权获取访问令牌。首先,您需要在 Google Cloud Console 中注册应用程序并获取 client_id 和 client_secret。
步骤 1. 配置 URL scheme
在 Info.plist 文件中添加回调的 scheme:
<key>CFBundleURLTypes</key><array> <dict> <key>CFBundleURLSchemes</key> <array> <string>com.googleusercontent.apps.YOUR_CLIENT_ID</string> </array> </dict></array>步骤 2. 授权代码
import OAuthSwift
let oauthswift = OAuth2Swift( consumerKey: "YOUR_CLIENT_ID", consumerSecret: "YOUR_CLIENT_SECRET", authorizeUrl: "https://accounts.google.com/o/oauth2/auth", accessTokenUrl: "https://oauth2.googleapis.com/token", responseType: "code")
// 保存对控制器的引用以展示 WebViewlet handler = SafariURLHandler(viewController: self, oauthSwift: oauthswift)oauthswift.authorizeURLHandler = handler
let state = generateState(withLength: 20)oauthswift.authorize( withCallbackURL: URL(string: "com.googleusercontent.apps.YOUR_CLIENT_ID:/oauth2callback")!, scope: "https://www.googleapis.com/auth/userinfo.email", state: state, parameters: [:]) { result in switch result { case .success(let (credential, response, parameters)): print("Access Token: \\(credential.oauthToken)") print("Refresh Token: \\(credential.oauthRefreshToken)") // 将令牌保存到 Keychain KeychainWrapper.standard.set(credential.oauthToken, forKey: "access_token") KeychainWrapper.standard.set(credential.oauthRefreshToken, forKey: "refresh_token") case .failure(let error): print("授权错误:\\(error.localizedDescription)")