OktaOidc 3.11.7

OktaOidc 3.11.7

Mike NachbaurIldar 维护。



OktaOidc 3.11.7

  • Okta 开发者

CI Status Carthage compatible Version License Platforms Swift

Okta Open ID Connect 库

这是此 SDK 的新版本,新的 pod 名称是 OktaOidc。旧的 OktaAuth pod 现已弃用。

此库是围绕 AppAuth-iOS Objective-C 代码的 Swift 包装器,用于作为 OAuth 2.0 + OpenID Connect 提供者与 Okta 通信,并遵循原生应用当前的最佳实践,使用 授权代码流 + PKCE

您可以在我们文档中的 Okta + iOS 页面上了解更多信息。您还可以下载我们的 示例应用程序

目录

入门

将 OktaOidc SDK 安装到项目中的方法是简单的。将此库集成到项目中最简单的方法是通过 CocoaPods

您还需要

  • 一个 Okta 账户,称为 组织(如果您需要一个,请免费注册 开发者组织)。
  • 一个 Okta 应用程序,配置为原生应用程序。这需要从 Okta 开发者控制台完成,您可以在 此处 找到说明。在跟随向导时,请使用默认属性。它们是为了与我们的示例应用程序一起使用而设计的。

注意:如果您想使用自己的应用内用户界面而不是网络浏览器,您可以使用我们的Swift认证SDK

支持的平台

iOS

Okta OIDC支持iOS 11及以上版本。

macOS

Okta OIDC支持macOS(OS X)10.14及以上版本。库同时支持自定义方案;通过一个小型嵌入服务器进行回环HTTP重定向。

安装

Swift包管理器

将以下内容添加到您的Package.swift文件中定义的dependencies属性。您可以使用majorVersionminor参数选择版本。例如

    dependencies: [
        .Package(url: "https://github.com/okta/okta-oidc-ios.git", majorVersion: <majorVersion>, minor: <minor>)
    ]

CocoaPods

只需将以下行添加到您的Podfile

pod 'OktaOidc'

然后将其安装到您的项目中

pod install --repo-update

Carthage

使用Carthage将此SDK集成到您的Xcode项目中,在Cartfile中指定它。

github "okta/okta-oidc-ios"

然后将其安装到您的项目中

carthage update --use-xcframeworks

注意:确保Carthage版本为0.37.0或更高,否则Carthage可能会失败。

使用指南

要了解此库的功能和身份验证流程概述,请查阅我们的开发者文档

您还可以浏览完整的API参考文档

配置参考

创建OIDC对象

在使用此SDK之前,您必须创建一个新的OktaOidc对象。您可以无参实例化OktaOidc,这意味着SDK将使用Okta.plist中的配置值。或者,您可以使用自定义配置创建OktaOidc

import OktaOidc

// Use the default Okta.plist configuration
let oktaOidc = OktaOidc()

// Use configuration from another resource
let config = OktaOidcConfig(/* plist */)
let config = OktaOidcConfig(/* dictionary */)

// Instantiate OktaOidc with custom configuration object
let oktaOidc = OktaOidc(configuration: config)

需要刷新令牌吗?刷新令牌是一种特殊令牌,用于生成额外的访问和ID令牌。确保在配置中包含offline_access作用域,以在应用中静默更新用户的会话!

属性列表

最简单的方法是在应用程序的捆绑包中创建一个属性列表。默认情况下,此库检查文件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/oauth2/default</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>

配置对象

或者,您可以通过具有所需值的字典创建配置对象(OktaOidcConfig

let configuration = OktaOidcConfig(with: [
  "issuer": "https://{yourOktaDomain}/oauth2/default",
  "clientId": "{clientID}",
  "redirectUri": "{redirectUri}",
  "logoutRedirectUri": "{logoutRedirectUri}",
  "scopes": "openid profile offline_access",
  // Custom parameters
  "login_hint": "[email protected]"
])

禁用认证会话的单一登录

您可以将OktaOidcConfig实例的noSSO标志设置为true来禁用SSO功能。

let configuration = OktaOidcConfig(with: {YourOidcConfiguration})
if #available(iOS 13.0, *) {
    configuration?.noSSO = true
}

注意该标志适用于iOS 13及更高版本。

令牌时间验证

通过实现OKTTokenValidator协议并设置tokenValidator变量,可以实现自定义令牌时间验证。

configuration?.tokenValidator = self

默认设置为OKTDefaultTokenValidator对象。

在Objective-C项目中使用

要在Objective-C项目中使用此SDK,您应该执行以下操作

  • 在您的Pod文件中添加use_frameworks!
  • 添加项目设置SWIFT_VERSION = 5.0。为此,请在Xcode中打开构建设置,选择编辑 -> 添加构建设置 -> 添加用户定义设置。指定SWIFT_VERSION5.0作为设置名称和相应的值。
  • 将自动生成的头文件OktaOidc/OktaOidc-Swift.h包含到源代码中。

API 参考

signInWithBrowser

通过简单地调用 signInWithBrowser 来启动授权流程。如果授权成功,该操作将在其回调中返回有效的 OktaOidcStateManager。客户端需要负责进一步存储和管理该管理器。

注意:可以通过指定带有 idp 参数的参数来传递 IDP。

iOS

oktaOidc.signInWithBrowser(from: viewController, additionalParameters: ["idp": "your_idp_here"]) { stateManager, error in
  if let error = error {
    // Error
    return
  }

  // stateManager.accessToken
  // stateManager.idToken
  // stateManager.refreshToken
}

示例应用 示例

macOS

// Create redirect server configuration and start local HTTP server if you don't want to use custom schemes
let serverConfig = OktaRedirectServerConfiguration.default
serverConfig.port = 63875
oktaOidc.signInWithBrowser(redirectServerConfiguration: serverConfig, additionalParameters: ["idp": "your_idp_here"]) { stateManager, error in
  if let error = error {
    // Error
    return
  }

  // stateManager.accessToken
  // stateManager.idToken
  // stateManager.refreshToken
}

signOutOfOkta

此方法在浏览器中结束用户的 Okta 会话。该方法将删除 Okta 的持久性 Cookie 并禁用 SSO 功能。

重要:此方法 不会 清除或吊销 Okta 颁发的令牌。使用 OktaOidcStateManagerrevokeclear 方法来终止您应用程序中用户的本地会话。

iOS

// Redirects to the configured 'logoutRedirectUri' specified in Okta.plist.
oktaOidc.signOutOfOkta(authStateManager, from: viewController) { error in
  if let error = error {
    // Error
    return
  }
}

示例应用 示例

macOS

// Create redirect server configuration and start local HTTP server if you don't want to use custom schemes
let serverConfig = OktaRedirectServerConfiguration.default
serverConfig.port = 63875
// Redirects to the configured 'logoutRedirectUri' specified in Okta.plist.
oktaOidc.signOutOfOkta(authStateManager: authStateManager, redirectServerConfiguration: serverConfig) { error in
  if let error = error {
    // Error
    return
  }
}

退出登录

此方法有助于执行多步骤退出流程。此方法提供您想要执行的操作选项,并且 SDK 将这些选项作为一个批次运行。可用的选项有

  • revokeAccessToken - SDK 撤销访问令牌
  • revokeRefreshToken - SDK 撤销刷新令牌
  • removeTokensFromStorage - SDK 从安全存储中删除令牌
  • signOutFromOkta - SDK 调用 signOutOfOkta
  • revokeTokensOptions - 撤销访问和刷新令牌
  • allOptions - 撤销令牌、从 Okta 退出登录以及从安全存储中删除令牌

SDK 执行的操作顺序

  1. 如果设置了选项,则撤销访问令牌。如果该步骤失败,则跳过第 3 步。
  2. 如果设置了选项,则撤销刷新令牌。如果该步骤失败,则跳过第 3 步。
  3. 如果设置了选项,则从安全存储中删除令牌。
  4. 如果设置了选项,则进行浏览器退出登录。

iOS

let options: OktaSignOutOptions = .revokeTokensOptions
options.insert(.signOutFromOkta)
oktaOidc?.signOut(authStateManager: authStateManager, from: viewController, progressHandler: { currentOption in
    if currentOption.contains(.revokeAccessToken) {
        // update progress
    } else if currentOption.contains(.revokeRefreshToken) {
        // update progress
    } else if currentOption.contains(.signOutFromOkta) {
        // update progress
    }
}, completionHandler: { success, failedOptions in
    if !success {
        // handle error
    }
})

macOS

// Create redirect server configuration and start local HTTP server if you don't want to use custom schemes
let serverConfig = OktaRedirectServerConfiguration.default
serverConfig.port = 63875
let options: OktaSignOutOptions = .revokeTokensOptions
options.insert(.signOutFromOkta)
oktaOidc?.signOut(authStateManager: authStateManager,
                  redirectServerConfiguration: serverConfig,
                  progressHandler: { currentOption in
    if currentOption.contains(.revokeAccessToken) {
        // update progress
    } else if currentOption.contains(.revokeRefreshToken) {
        // update progress
    } else if currentOption.contains(.signOutFromOkta) {
        // update progress
    }
}, completionHandler: { success, failedOptions in
    if !success {
        // handle error
    }
})

authenticate

如果您已经登录到 Okta 并拥有有效的会话令牌,则可以通过调用 authenticate(withSessionToken:) 来完成授权。授权成功后,此操作在回调中返回一个有效的 OktaOidcStateManager。客户端负责进一步存储和维护管理器。

oktaOidc.authenticate(withSessionToken: token) { stateManager, error in
  self.hideProgress()
  if let error = error {
    // Error
    return
  }

  // stateManager.accessToken
  // stateManager.idToken
  // stateManager.refreshToken
}

示例应用程序 示例

stateManager

令牌安全存储在钥匙串中,可以通过访问OktaOidcStateManager检索。

stateManager?.accessToken
stateManager?.idToken
stateManager?.refreshToken

用户负责存储由signInWithBrowserauthenticate操作返回的OktaAuthStateManager。要存储管理器,请调用writeToSecureStorage方法

oktaOidc.signInWithBrowser(from: self) { stateManager, error in
  stateManager.writeToSecureStorage()
}

示例应用示例

要检索存储的管理器,请调用readFromSecureStorage(for:)并传入对应您感兴趣管理器的Okta配置。

guard let stateManager = OktaOidcStateManager.readFromSecureStorage(for: oktaConfig) else {
    // unauthenticated
}

//authenticated 
// stateManager.accessToken
// stateManager.idToken
// stateManager.refreshToken

示例应用示例

注意:在OktaOidc SDK 3.0中,我们添加了对多个OAuth 2.0账户的支持。因此,开发人员可以在一个应用程序中使用Okta端点、社交端点和其他端点。因此,OktaOidcStateManager使用基于配置的复合键存储在钥匙串中。为了保持向后兼容性,有一个方法readFromSecureStorage()尝试读取以传统方式存储的OktaOidcStateManager,以便用户可以在切换到较新版本的SDK后检索先前存储的OktaOidcStateManager

introspect

调用内省端点检查指定令牌的有效性。

stateManager?.introspect(token: accessToken, callback: { payload, error in
  guard let isValid = payload["active"] as? Bool else {
    // Error
    return
  }

  print("Is token valid? \(isValid)")
})

示例应用示例

renew

由于访问令牌传统上生命周期很短,您可以通过用刷新令牌交换新令牌来续期过期的令牌。请查阅配置参考以确保您的应用程序已正确配置。

stateManager?.renew { newAccessToken, error in
  if let error = error else {
    // Error
    return
  }

  // renewed TokenManager
}

示例应用示例

revoke

调用撤销端点以撤销指定的令牌。

stateManager?.revoke(accessToken) { response, error in
  if let error = error else {
    // Error
    return
  }

  // Token was revoked
}

示例应用示例

getUser

通过存储的访问令牌调用OpenID Connect UserInfo端点以返回用户声明信息。

stateManager?.getUser { response, error in
  if let error = error {
    // Error
    return
  }

  // JSON response
}

示例应用示例

清除

通过从密钥链中删除缓存的令牌来删除本地认证状态。

警告: SDK 删除了应用程序可访问的所有密钥链项。

stateManager.clear()

示例应用 示例

开发

运行测试

要进行端到端测试,请更新 Okta.plist 文件以匹配在 先决条件 中指定的配置。接下来,导出以下环境变量

export USERNAME={username}
export PASSWORD={password}
export CLIENT_ID={clientId}
export ISSUER=https://{yourOktaDomain}/oauth2/default
export REDIRECT_URI={redirectUri}
export LOGOUT_REDIRECT_URI={logoutRedirectUri}

# Run E2E end Unit tests
bash ./scripts/build-and-test.sh

注意: 您可能需要更新模拟器设备以匹配您的 Xcode 版本。

修改网络请求

您可以跟踪和修改 OktaOidc 发出的网络请求。为此,创建一个遵循 OktaNetworkRequestCustomizationDelegate 协议的对象,并将其设置到一个 OktaOidcConfig 实例的 requestCustomizationDelegate 属性上。

let configuration = OktaOidcConfig(with: {YourOidcConfiguration})
configuration.requestCustomizationDelegate = {YourDelegateInstance}

例如,代理可以按如下方式实现

extension SomeNSObject: OktaNetworkRequestCustomizationDelegate {

    func customizableURLRequest(_ request: URLRequest?) -> URLRequest? {
        guard var modifiedRequest = request else {
            return nil
        }
        modifiedRequest.setValue("Some value", forHTTPHeaderField: "custom-header-field")
        print("Okta OIDC network request: \(modifiedRequest)")
        return modifiedRequest
    }

    func didReceive(_ response: URLResponse?) {
        guard let response = response else {
            return
        }
        print("Okta OIDC network response: \(response)")
    }
}

注意: 极力建议将原始 URLRequest 对象的现有所有参数完全复制到修改后的请求中,不要做任何更改。改变这些数据可能导致网络请求失败。如果 customizableURLRequest(_:) 方法返回 nil,则将使用默认请求。

迁移

从3.10.x迁移到3.11.x

SDK okta-oidc-ios 在错误处理方面有重大变更。请遵循以下指南来更新您的代码。

  • APIError 已重命名为 api
  • api 错误有一个额外的参数 underlyingError,它是可选的并指示错误的来源。
  • 引入了一个新的错误 authorization(error:description:)
  • authorization 错误出现在授权服务器因授权过程中出现错误而失败时。
  • unexpectedAuthCodeResponse(statusCode:) 有一个错误代码参数。
  • OktaOidcError 符合 CustomNSError 协议。这意味着您可以转换错误为 NSError 并获取 codeuserInfodomainunderlyingErrors
  • OktaOidcError 符合 Equatable 协议。可以使用运算符 == 对错误进行比较,以判断它们是否相等,或者使用运算符 != 比较它们是否不相等。

已知问题

iOS 显示权限对话框({App} Wants to Use {Auth Domain} to Sign In)用于 Okta 登出流程

这是一已知 iOS 的问题,iOS 提供没有任何好的方法来终止活动的身份验证会话并删除 SSO 饼干。目前唯一正确的方法是使用 ASWebAuthenticationSession 类来终止会话。ASWebAuthenticationSession 删除了所有 SSO 饼干,但显示了 Sign In 权限对话框。🤯

您还可以考虑以下解决方法:

  • 如果不需要 SSO 功能,请使用 OIDC 配置对象中的 noSSO 选项。请注意,此选项仅适用于 iOS 13 及以上版本。
  • 分叉存储库并更改用户代理实现(OIDExternalUserAgentIOS.m),仅使用 SFSafariViewController。此方法的一些潜在问题在此处进行描述这里

贡献

我们欢迎对所有开源项目的贡献。请参阅贡献指南了解如何构建贡献。