无密码 1.0.0

无密码 1.0.0

Victor GermanisAnders Bitwarden维护。



无密码 1.0.0

  • Bitwarden

Passwordless by Bitwarden

Passwordless.dev iOS 客户端 SDK

此 SDK 的目的是能够通过 Passwordless.dev 管理系统的帮助,轻松将 passkeys 集成到您的 iOS 应用中。为确保正确使用,提供了一个名为 DemoPasswordless 的示例项目,并将其包含在此仓库中以及 SDK 内。

系统概述

Passwordless.dev 由三个关键部分组成:

  1. 一个开源客户端 SDK(例如,此 iOS SDK),由您的应用/网站使用,在终端用户的设备上初始化 passkey 授权请求,并请求与 passwordless.dev API 交互。
  2. 一个公共 RESTful API,用于完成 FIDO2 WebAuthn 密码学交换。
  3. 一个私有 RESTful API,用于初始化密钥注册、验证登录和检索终端用户的密钥。

有关详细信息,请参阅 Passwordless.dev 文档

apple-app-site-association

Apple 需要设置相关域以执行 passkey 注册和声明。有关设置 apple-app-site-association 的更多详细信息,请参阅 Apple 的文档

对于 passkeys,您需要为您的应用设置一个 webcredentials 部分。

您可以在此示例中查看与应用此仓库中提供的 DemoPasswordless 应用对应的 apple-app-site-association。

以下是在 demo.passwordless.dev 上托管 AASA 时 Xcode 中应呈现的底盘示例

Entitlements

使用 iOS SDK 入门

需求

  • **最低 iOS 版本**: iOS 16
  • 附加功能
    • **相关域**:需要添加 AASA 文件托管的域。

Swift 包管理器

您可以通过 Swift 包管理器 将 SDK 添加到您的项目中。然后您可以使用 import Passwordless 访问 SDK 功能。

CocoaPods

您可以通过 CocoaPods 将 SDK 添加到您的项目中。在您的 Podfile 中指定以下内容:

pod 'Passwordless', '~> 0.0.1'

初始化

SDK 提供一个需要使用 PasswordlessConfig 配置初始化的 PasswordlessClient 对象。该配置包含与 Passwordless.dev 交互所需的 API URL 和 API 密钥。它还需要代表您托管具有您的应用团队 ID 和 bundle ID 的 apple-app-site-association 文件的服务的域名依赖方 ID。

您需要注册 Passwordless.dev 以获取 API 密钥。

以下是一个配置示例

let passwordlessClient = PasswordlessClient(
    config: PasswordlessConfig(
        apiKey: "<YOUR API KEY>",
        rpId: "demo.passwordless.dev"
    )
)

注册

  1. 使用给定的用户名从您的公共 RESTful API 请求注册令牌。
  2. 通过register(token:)函数将注册令牌传递给PasswordlessClient。这将提示用户使用生物识别创建用于验证的本地私钥,并将公钥发送到Passwordless.dev API。完成后,将返回一个验证令牌。有关可能抛出的错误,请参阅错误部分
let verifyToken = try await passwordlessClient.register(token: registrationToken)
  1. 将验证令牌传递到您的公共RESTful API进行验证,并返回一个授权令牌。用户现在已登录到您的应用。

Registration Flow

登录

passkey 登录有两种主要方法:自动填充和别名。还提供了signinWithDiscoverable()signIn(userId:),以便用于更复杂的使用场景。

A. 自动填充

当用户点按用户名字段并显示键盘时,这就是自动填充的情况。如果用户点按键盘上方的自动填充选项,那么这就是自动填充的方法。为了正确工作,当您的视图首次出现时,您必须调用signInWithAutofill。这样,当键盘出现时,操作系统将准备好要显示的结果。

  1. 当您的视图首次出现时调用signInWithAutofill()。一旦完成,将返回一个验证令牌。
    • 此函数将等待用户点按自动填充项、在passkey对话框中取消或发生错误。
    • 如果抛出错误,您的应用将需要决定是否重新启动自动填充登录过程。
    • 如果它未运行,则键盘上不会显示任何选项,因此通常仅在authorizationCancelled情况下重新启动过程才有意义。
    • 收到authorizationError可能表明您的应用内部有一些配置不正确,因此最好不再次运行自动填充以防止无限循环错误。请参阅错误部分,了解可能抛出的错误。
let verifyToken = try await passwordlessClient.signInWithAutofill()
  1. 将验证令牌传递到您的公共RESTful API进行验证,并返回一个授权令牌。用户现在已登录到您的应用。

Auto Fill Sign in Flow

B. 别名

当用户输入用户名并点击视图中用于登录的按钮时,这就是别名的情况。这将为用户提供不同的passkey窗口版本进行选择。

  1. 使用给定的别名调用signIn(alias:)。一旦完成,将返回一个验证令牌。有关可能抛出的错误,请参阅错误部分
let verifyToken = try await passwordlessClient.signIn(alias: username)
  1. 将验证令牌传递到您的公共RESTful API进行验证,并返回一个授权令牌。用户现在已登录到您的应用。

Alias Sign in Flow

C. 可发现

如果您希望手动显示passkey模态而不用键盘快捷键或让用户输入别名。

D. 用户 Id

如果您已有用户 Id并且想进行声明过程。

错误响应

PasswordlessClient对象可以抛出以下错误

错误 描述
authorizationCancelled 从密钥凭证提供者取消了操作系统授权。
authorizationError(Error) 从密钥凭证提供者处失败的操作系统授权。
internalErrorDecodingJson(Error) 从网络响应中解码json到对象时出现问题。
internalErrorEncodingPayload(Error) 在为网络请求编码json时出现问题。
internalErrorInvalidURL(String) 用于发出网络请求的url无效。
internalErrorNetworkRequestFailed(Error) 发出网络请求时发生错误。
internalErrorNetworkRequestResponseError(Int?, PasswordlessErrorResponse?) 在网络请求中发生错误响应,给定状态代码和错误响应(如有)。
internalErrorUnableToDecodeChallenge 提供的挑战格式不正确。
internalErrorUnableToEncodeUserId 用户 ID 无法编码为 base 64 Url。

对于internalErrorNetworkRequestResponseError,可以提供PasswordlessErrorResponse,其中包含有关响应中错误的详细信息。以下是一个可能返回的响应错误示例

{
  "type": "https://docs.passwordless.dev/errors#missing_register_token",
  "title": "The token you sent was not correct. The token used for this endpoint should start with 'register_'. Make sure you are not sending the wrong value.",
  "status": 400,
  "errorCode": "missing_register_token"
}

以下是如何在您的应用中查看此示例

do {
    let verifyToken = try await passwordlessClient.signIn()
}
catch PasswordlessClientError.authorizationCancelled {
    print("Cancelled")
}
catch let PasswordlessClientError.internalErrorNetworkRequestResponseError(code, response) {
    print("Network Error occurred. Response status code: \(code ?? -1)")
    dump(response)
}
catch {
    print("Some other error occurred: \(error)")
}

示例应用

本项目包含一个名为DemoPasswordless的示例应用程序。需要注意,如果您计划运行此应用程序,您必须事先进行一些配置。

  1. 密钥认证与存储在您的公共API上的apple-app-site-association (AASA) 文件直接关联。
  2. 运行应用程序时,您的开发者帐户必须在对应的AASA文件指定的Apple团队中,并且有一个匹配的包标识符。

例如,假设您的AASA文件如下所示

{
  "webcredentials": {
    "apps": [
      "Q999999997.com.8bit.bitwarden.passwordlessios"
    ]
  }
}

为了正确运行演示应用程序,应用程序的包标识符必须为com.8bit.bitwarden.passwordlessios。此外,您的个人开发者帐户必须有权访问团队标识符Q999999997

DemoServices.swift文件中,可信方ID(rpID)应设置为存放此AASA文件的域名。

参考资料