Swift 的 Okta 移动 SDK
Swift 的 Okta 移动 SDK 替代了我们的旧版移动 SDK(例如 okta-oidc-ios)并使
- 开发过程更流线
- 提高您代码中 Okta 部分的可维护性
- 更容易扩展功能
- 支持以前难以实现或不可行的情况。
此新 SDK 作为平台构建,使您可以根据应用程序需求选择所需组件。
目录
发布状态
此库使用语义版本控制并遵循 Okta 的库版本策略。
版本 | 状态 |
---|---|
1.4.2 |
最新的发布版可以在 发行版页面 上找到。
需要帮助?
如果您在使用 SDK 时遇到问题,您可以
- 查看 AuthFoundation、OktaOAuth2 和 WebAuthenticationUI 的 API 文档
- 在 Okta 开发者论坛 上提问
- 在此处 GitHub 上发布 问题(对于代码错误)
SDK 架构
本 SDK 包含多个不同的库,每个库都有详细的文档。
graph TD;
AuthFoundation-->OktaOAuth2;
OktaOAuth2-->WebAuthenticationUI;
- AuthFoundation -- 管理凭证的公共类,作为其他库的基础。
- OktaDirectAuth -- 提供无浏览器的高级认证(EA)的直接认证功能。
- OktaOAuth2 -- 适用于高级用例的 OAuth2 认证功能。
- WebAuthenticationUI -- 使用基于 Web 的 OIDC 流进行用户认证。
此 SDK 使您能够构建或支持各种不同的认证流程和方法。
开发路线图
本 SDK 正在积极开发中,并计划进行未来扩展。目前,我们正在寻求开发社区的反
- 整体 SDK 及其组件
- API 及整体开发者体验
- 可能遗漏或不符合您应用程序需求的用例或功能
- 关于未来发展的建议
- 关于此新方向的任何其他评论或反馈。
主要功能
此库引入了几个关键功能和能力,以下列出一些显著的改进。
功能 |
---|
简单的基于 OIDC 的 Web 签到 |
凭证管理(安全存储、检索等) |
多令牌处理(存储和使用针对多个用户、作用域等的令牌) |
授权代码流 |
原生 SSO/令牌交换流 |
设备授权 Grants 流 |
资源所有者流 |
简化 JWT 解析和处理 |
使用凭证令牌简化 URLSession 请求的授权 |
许多扩展点用于自定义、监控和跟踪 |
入门
要开始,你需要
- 一个Okta账户,称为组织(如果您需要的话,可以免费注册一个开发者组织)。
- 一个配置为“原生应用”的Okta应用程序。使用Okta管理员控制台创建应用程序,按照向导操作并使用默认属性。
- Xcode 13.x,针对支持的任何平台和目标版本(见下方的支持策略)。
有关如何利用此SDK的示例,请参阅此存储库中包含的示例应用程序。
安装
Swift包管理器
将以下内容添加到您的Package.swift
文件中定义的dependencies
属性。您可以通过使用majorVersion
和minor
参数来选择版本。例如
dependencies: [
.Package(url: "https://github.com/okta/okta-mobile-swift.git", majorVersion: <majorVersion>, minor: <minor>)
]
CocoaPods
只需将以下行添加到您的Podfile
pod 'OktaWebAuthenticationUI'
然后将其安装到您的项目中
pod install --repo-update
如果您只对消费OktaOAuth2库感兴趣,请使用以下方法
pod 'OktaOAuth2'
如果您正在参与Okta Direct Authentication API的Early Access预览,请使用以下方法
pod 'OktaDirectAuth'
使用指南
使用OIDC进行Web认证
在您的应用程序中集成认证的最简单方法是通过网页浏览器使用基于授权代码流的OIDC。
配置您的OIDC设置
在您使用Okta开发控制台中的应用程序设置之前,您需要创建客户端配置。最简单的方法是使用名为Okta.plist
的配置文件来指定这些设置。请确保创建该文件并包含以下字段:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>issuer</key>
<string>https://{yourOktaDomain}.com</string>
<key>clientId</key>
<string>{clientId}</string>
<key>redirectUri</key>
<string>{redirectUri}</string>
<key>logoutRedirectUri</key>
<string>{logoutRedirectUri}</string>
<key>scopes</key>
<string>openid profile offline_access</string>
</dict>
</plist>
或者,您也可以在下文将要讨论的下一个部分中,将这些值提供给即将讨论的WebAuthentication
构造函数。
创建一个Web认证会话
一旦您在Okta.plist
文件中配置了您的应用程序设置,共享配置将自动通过WebAuthentication.shared
单例属性获得。这样一来,您可以使用便利方法WebAuthentication.signIn(from:)
提示用户登录。
import WebAuthenticationUI
func signIn() async {
let token = try await WebAuthentication.signIn(from: view.window)
let credential = try Credential.store(token)
}
函数signIn(from:)
返回一个令牌,并通过使用Credential
类,您可以在应用程序中保存该令牌并使用它。
基于设备代码流授权的认证
对于无头设备或难以使用键盘的设备(例如AppleTV),您的应用程序可以直接使用OktaOAuth2配合DeviceAuthorizationFlow
类。这将使您能够向用户提供一个易于记忆的代码,他们可以在另一个设备上使用该代码来授权您的应用程序。
使用起来很简单
- 创建一个
DeviceAuthorizationFlow
实例
let flow = DeviceAuthorizationFlow(
issuer: URL(string: "https://example.okta.com")!,
clientId: "abc123client",
scopes: "openid offline_access email profile")
- 开始一个认证会话以接收代码和授权URL以向用户展示。
let context = try await flow.start()
let code = context.userCode
let uri = context.verificationUri
- 等待用户从另一个设备中授权应用程序。
let token = try await flow.resume(with: context)
原生化单点登录流程认证
当使用device_sso
作用域时,您的应用程序可以接收一个“设备密钥”,它可以与您的用户ID令牌一起使用来交换新的凭据。为了在您的应用程序中使用,您将使用TokenExchangeFlow
来交换这些令牌集。
let flow = TokenExchangeFlow(
issuer: URL(string: "https://example.okta.com")!,
clientId: "abc123client",
scopes: "openid offline_access email profile",
audience: .default)
let token = try await flow.start(with: [
.actor(type: .deviceSecret, value: "DeviceToken"),
.subject(type: .idToken, value: "IDToken")
])
使用用户名/密码进行认证
对于简单的认证用例,您可以使用ResourceOwnerFlow
类通过纯用户名和密码进行认证。
注意:ResourceOwnerFlow类已被标记为已过时,因为它的功能正被更全面的功能所取代——OktaDirectAuth库。
let flow = ResourceOwnerFlow(issuer: URL(string: "https://example.okta.com")!,
clientId: "abc123client",
scopes: "openid offline_access email profile")
let token = try await flow.start(username: "jane.doe", password: "secretPassword")
使用直接认证(EA)进行认证
对于简单的认证用例,您可以使用ResourceOwnerFlow
类通过纯用户名和密码进行认证。
注意: Okta直接认证API目前处于早期访问(EA)状态,尚未普遍可用。
let flow = DirectAuthenticationFlow(issuer: URL(string: "https://example.okta.com")!,
clientId: "abc123client",
scopes: "openid offline_access email profile")
switch try await flow.start("[email protected]", with: .password("secretPassword")) {
case .success(let token):
// Store the token
case .mfaRequired(_):
// Continue authentication
}
有关更多信息,请参阅OktaDirectAuth API文档。
存储和使用令牌
一旦用户认证成功,并且您获得了Token
对象,您的应用程序可以存储并使用这些凭据。最直接的方法是使用Credential.store(_:tags:security:)
函数。
let credential = try Credential.store(token)
作为便利的方法,SDK在Credential
类上提供了一个default
静态属性。这提供了一个简单的识别用户体验是否当前认证,并快速访问该用户的凭据的方法。当存储新的凭据时,如果尚未存储,它将自动被指定为默认值。
if let credential = Credential.default {
// The user is signed in. Start by refreshing it.
try await credential.refreshIfNeeded()
}
通过唯一标识符查找凭据
当令牌被存储时,它会分配一个唯一的ID,这可以用作区分不同令牌并在将来检索令牌。
let tokenId = token.id
// Later, retrieve the token
if let credential = try Credential.with(id: tokenId) {
// Use the credential
}
使用自定义标签分配和查找凭据
对于更复杂的应用程序,您可能需要管理多个凭据(例如,多用户登录、应用扩展的不同令牌、应用不同部分的具体作用域等)。为了更容易地区分凭据,您可以向它们分配标签,这些标签后来可以用于识别它们。
try Credential.store(token, tags: ["customTag": "someValue"])
可以根据这些标签检索凭据。
if let credential = try Credential.find(where: { $0.tags["customTag"] == "someValue" }).first {
// Use the credential
}
凭据的标签可通过其 tags
属性获取,并且可以事后更改。
if !credential.tags.contains("someCustomTag") {
credential.tags["someCustomTag"] = "someValue"
}
// Or use the following method to intercept exceptions
try credential.setTags(["customTag": "someValue"])
使用ID令牌断言查找凭据
此SDK简化了对JWT令牌及其断言的访问。事实上,令牌的 idToken
属性会自动公开为 JWT
实例。使用此方法,您可以根据与其令牌相关联的断言列出来检索凭据。
if let credential = try Credential.find(where: { $0.email == "[email protected]" }).first {
// Use the credential
}
配额限制处理
如果在一个给定时间内发出了太多请求,Okta API将返回429响应。请参阅Okta的配额限制获取哪个端点受配额限制的完整列表。此SDK在429错误上自动重试请求。默认配置如下
配置选项 | 说明 |
---|---|
maximumCount | 重试次数。默认值是 3 。 |
自定义配额限制
为了自定义如何处理速率限制,遵循APIClientDelegate
协议,实现shouldRetry(request:rateLimit:)
方法,并将您的类作为适宜客户端的代理。当通过该客户端发送的任何请求接收HTTP 429错误响应时,它将允许您自定义速率限制行为。
import AuthFoundation
func login() {
// Configure your authentication flow, before running the following command
flow.client.add(delegate: self)
}
extension OAuth2Client {
public func api(client: APIClient, shouldRetry request: URLRequest) -> APIRetry {
return .doNotRetry
}
}
有关更多信息,请参考APIRetry
枚举的API文档。
从旧SDK迁移
此SDK集旨在替代以下SDK
如果您的应用程序目前正在使用OktaOidc,已经建立了将现有用户迁移到新SDK的设施。有关更多信息,请参阅SDKVersion.Migration
类的详细说明。
运行示例
有几个应用程序可展示此SDK的不同工作流程。有关更多信息,请参阅示例应用程序。
支持策略
此策略定义了支持Xcode、Swift和平台版本(iOS、macOS、tvOS和watchOS)的范围。
Xcode
目前唯一受支持的 Xcode 版本是那些可以用于提交应用至 App Store 的版本。一旦某个 Xcode 版本不再受支持,在次要版本中停止支持它不会被视为重大更改,并将在次要版本中进行。
Swift
最低支持的 Swift 5 次要版本是与旧支持的 Xcode 版本一同发布的版本。一旦某个 Swift 5 次要版本不再受支持,在次要版本中停止支持它不会被视为重大更改,并将在次要版本中进行。
平台
仅支持最近的 4 个主要平台版本,除非存在平台限制,限制了我们对旧版本的能力。
平台 | 受支持 | 尽力而为 |
---|---|---|
iOS | 12.0 | 9.0 |
tvOS | 12.0 | 10.0 |
watchOS | 8.0 | 7.0 |
macCatalyst | 13.0 | 13.0 |
macOS | 12.0 | 10.11 |
一旦某个平台版本不再受支持,在次要版本中停止支持它不会被视为重大更改,并将在次要版本中进行。例如,当 iOS 16 发布时,iOS 12 将停止受支持,并可能在某个次要版本中被取消支持。
对于 macOS,年度命名的版本被视为政策中的主要平台版本,而不管版本号的实际数字如何。
注意:旧操作系统版本以尽力而为的方式进行支持。除非存在限制 API 导致 SDK 在旧操作系统版本上无法有效工作的限制,否则最低要求不会更改。
此外,Linux 兼容性被视为尽力而为,并不被正式支持。
旧 SDK 支持
在 okta-mobile-swift SDK 成为一般可用产品后,我们打算在该新库中开发所有新功能。我们计划对 okta-oidc-ios (以及 okta-mobile-swift 替换的其他其他旧 SDK) 进行关键错误和安全修复,以应对可预见的未来。
开发
保护测试配置
此存储库包含两个文件,位于 Samples/Shared
目录中,用于向自动化测试及示例应用公开测试凭据。
为了防止这些文件意外更改,建议你在克隆此存储库后使用以下命令:
git config core.hooksPath ./.githooks
这将在提交更改前运行检查以确保这些文件未被修改。
运行测试
您可以使用以下命令在 macOS 上从命令行运行测试:
swift test
或者,如果您想在 Linux 中运行测试,您可以利用 macOS 环境中的 Docker 来运行 Linux 测试。
docker run --rm --privileged --interactive --tty \
--volume "$(pwd):/src" --workdir "/src" swift:5.6.1 \
swift test
已知问题
参与贡献
我们乐意接受贡献和PR!请参阅贡献指南了解如何构建贡献。