Okta Mobile SDK for Swift
Okta Mobile SDK 替代了我们之前遗留下来的移动 SDK(例如 okta-oidc-ios),并支持
- 简化开发
- 提高代码中 Okta 部分的可维护性
- 更容易扩展功能
- 支持之前难以或无法实施的使用案例。
这个新的 SDK 是作为一个平台建设的,允许您根据应用需要选择组件。
目录
发布状态
此库使用语义版本,并遵循 Okta 的 库版本策略。
版本 | 状态 |
---|---|
1.4.2 |
可以在 发布页面 上找到最新发布版。
需要帮助?
如果您在使用 SDK 时遇到问题,可以
- 请查看以下API文档:AuthFoundation、OktaOAuth2 以及 WebAuthenticationUI
- 在 Okta 开发者论坛 上提问
- 在GitHub上此处提交 问题(针对代码错误)
SDK 架构
此SDK由几个不同的库组成,每个库都拥有详细文档。
graph TD;
AuthFoundation-->OktaOAuth2;
OktaOAuth2-->WebAuthenticationUI;
- AuthFoundation -- 用于管理凭据的常见类,也是其他库的基础。
- OktaDirectAuth -- 针对高级无浏览器身份验证(EA)的直接身份验证功能。
- OktaOAuth2 -- 针对高级用例的OAuth2身份验证功能。
- WebAuthenticationUI -- 使用基于Web的OIDC流对用户进行身份验证。
此SDK使您能够构建或支持各种不同的身份验证流程和方法。
开发路线图
此SDK正在积极开发中,未来将进行扩展。目前,我们正在寻求开发社区反馈以评估以下内容:
- 总体SDK及其组件
- API以及对开发者体验的整体评价
- 可能遗漏或不符合您应用需求的用例或功能
- 对未来开发的建议
- 对本新方向的任何其他评论或反馈。
关键特性
此库引入了几个关键特性和功能,以下是一些显著的改进:
特性 |
---|
简单的基于Web的OIDC登录 |
凭据管理(安全存储、检索等) |
多令牌处理(存储和使用多个用户、范围等的令牌) |
授权码流程 |
原生SSO / 令牌交换流程 |
设备授权码授权流程 |
资源所有者流程 |
简单的JWT解析和处理 |
使用凭证令牌简化NSURLSession请求的授权 |
提供多个扩展点,以支持定制性、监控和追踪 |
入门
要开始使用,你需要
- 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 的早期访问预览,请使用以下方式
pod 'OktaDirectAuth'
使用指南
使用 OIDC 进行网络身份验证
在您的应用程序中集成的最简单方法是通过网络浏览器使用 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
构造函数中提供这些值。
创建网络身份验证会话
一旦你在 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),你的应用程序可以使用 DeviceAuthorizationFlow
类直接与 OktaOAuth2 一起使用。这将允许你向用户提供一个易于记住的代码,他们可以在其他设备上使用它来授权你的应用程序。
使用非常简单
- 创建
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)
使用本地 SSO 流进行身份验证
当使用 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 Direct Authentication 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令牌及其声明的访问。事实上,Token的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
已知问题
贡献
我们欢迎接受贡献和PRs!请参阅贡献指南以了解如何构建贡献。