如何在 Amazon Cognito 用户池中使用记住的设备?

上次更新时间:2020 年 1 月 8 日

我想跟踪 Amazon Cognito 用户池中的用户用于登录我的应用程序的设备。该如何操作?

简短描述

Amazon Cognito 可以跟踪和记住用户池中的用户用于登录的设备。通过启用设备记忆功能,您可以设置登录限制(例如,限制从某个设备登录)。或者,您可以让用户跳过同一设备上的重复登录。有关更多信息,请参阅指定用户池设备跟踪设置

注意:记忆设备功能仅可用于 USER_SRP_AUTH 身份验证流程。此外,此功能需要为用户池启用多重身份验证 (MFA)

记住设备是一个两步过程:

  • 确认新的设备。从设备启动身份验证,然后使用 Amazon Cognito 进行确认以获取唯一的设备标识符。
  • 验证已确认的设备。从已确认的设备启动身份验证,以在随后的登录尝试中跳过 MFA 步骤。

解决方法

注意:以下说明概要描述了在应用程序客户端代码中进行的 Amazon Cognito API 调用。如果您使用的是客户端开发工具包,例如适用于 Android 或 iOS 的 AWS 移动软件开发工具包,则大部分实现都由工具包处理。

设置记住的设备

  1. Amazon Cognito 控制台中,选择管理用户池,然后选择您的用户池。
  2. 在左侧导航窗格中的一般设置下,选择设备
  3. 对于您是否想要记住您用户的设备,请选择始终用户选择加入。有关更多信息,请参阅使用 Amazon Cognito 跟踪和记住您用户池中的设备
  4. 对于您是否想要在多重身份验证 (MFA) 期间使用记住的设备阻止第二因素,请选择。有关更多信息,请参阅使用记住的设备来阻止多重身份验证 (MFA)
    注意:如果这些选项不出现,则 MFA 未启用。要设置 MFA,在左侧导航窗格中选择 MFA 和验证
  5. 选择保存更改

有关更多信息,请参阅指定用户池设备跟踪设置

调用 SetUserMFAPreference

在您应用程序的客户端代码中,调用 SetUserMFAPreference API 以为要使用的 MFA 方法将 MFA 首选项设置为 true

调用 InitiateAuth

在您应用程序的客户端代码中,调用 InitiateAuth API 来获取设备密钥。在此 API 请求中,确保包含以下请求参数

  • AuthFlow。使用 USER_SRP_AUTH
  • AuthParameters。包含身份验证参数 USERNAMESRP_ASECRET_HASH
    注意:仅当您的应用程序客户端配置了客户端密钥时,才需要SECRET_HASH

使用以下公式计算 SRP_A

SRP_A = ga (mod N)

  • 使用 AWS Amplify (JavaScript) GitHub 存储库上 AuthenticationHelper.js 中定义的 g
  • a = 128 个随机字节

有关更多信息,请参阅请求语法您选择的 AWS 开发工具包的 API 参考

为 MFA 质询调用 RespondToAuthChallenge

应用程序客户端调用 InitiateAuth API 之后,您的 Amazon Cognito 用户池将根据您启用的 MFA 方法返回一系列 MFA 质询。

您的应用程序必须使用 RespondToAuthChallenge API 应答这些质询。例如,如果您在用户池中启用了 SMS 文本消息 MFA,则参数 ChallengeName 要包含值 SMS_MFA。有关更多信息,请参阅请求语法您选择的 AWS 开发工具包的 API 参考

存储设备密钥

应答所有 MFA 质询后,Amazon Cognito 会在 NewDeviceMetadataType 字段中以 DeviceGroupKey 和唯一的 DeviceKey 进行响应。

如果您在浏览器中使用适用于 Android、iOS 或 JavaScript 的 AWS 移动软件开发工具包,则这些密钥将由应用程序自动移至设备的本地存储中。如果您使用的是其他 AWS 开发工具包,请确保为您的应用程序设计类似的密钥存储解决方案。

调用 ConfirmDevice

对于 DeviceGroupKeyDeviceKey,使用安全远程密码 (SRP) 协议创建一个秘钥,该协议会生成一个 salt 和一个密码验证程序。通过包含以下请求参数ConfirmDevice API 调用将这些传递到 Amazon Cognito:

  • AccessToken。使用对于用户有效的访问令牌。
  • DeviceKey。用从 Amazon Cognito 返回的设备唯一密钥。
  • DeviceName。使用您给设备指定的名称。(AWS 移动软件开发工具包使用用户代理。)
  • DeviceSecretVerifierConfig。包括 Salt(16 个随机字节,以 base64 编码)和 PasswordVerifier

对于 PasswordVerifier:使用以下公式:

PasswordVerifier = g(salt + FULL_PASSWORD) (mod N)

  • 使用 AWS Amplify (JavaScript) GitHub 存储库上 AuthenticationHelper.js 中定义的 g
  • FULL_PASSWORD = SHA256_HASH(DeviceGroupKey + username + ":" + RANDOM_PASSWORD)
  • RANDOM_PASSWORD = 40 个随机字节,以 base64 编码
  • 使用 AWS Amplify (JavaScript) GitHub 存储库上 AuthenticationHelper.js 中定义的 N

有关更多信息,请参阅请求语法您选择的 AWS 开发工具包的 API 参考

(可选)调用 UpdateDeviceStatus

在设置记住用户池中的设备时,如果选择始终,则可以跳过此步骤。如果您选择用户选择加入,您必须包含 UpdateDeviceStatus API 调用。

注意:如果您使用 Amazon Cognito Identity SDK for JavaScript,则必须调用setDeviceStatusRememberedsetDeviceStatusNotRemembered。有关更多信息,请参阅 GitHub 上开发工具包 README 文件中的 使用情况

当您为应用程序的用户提供记住其设备的选项时,请确认该设备在您的用户池中将作为“未记忆”来跟踪。 您必须询问用户是否要记住其设备,然后使用 UpdateDeviceStatus API 发送其选择。

注意:当需要选择加入时,用户必须选择加入才能记住其设备并阻止 MFA 质询。

使用设备密钥调用 InitiateAuth

在您应用程序的客户端代码中,调用 InitiateAuth API 来验证记住的设备。在此调用中,在请求参数中包含设备密钥,如下所示:

  • AuthFlow。使用 USER_SRP_AUTH
  • AuthParameters。包含身份验证参数 USERNAMESRP_ADEVICE_KEY

有关更多信息,请参阅请求语法您选择的 AWS 开发工具包的 API 参考

为 DEVICE_SRP_AUTH 调用 RespondToAuthChallenge

应用程序客户端使用有效的设备密钥进行 InitiateAuth API 调用后,您的 Amazon Cognito 用户池将返回 DEVICE_SRP_AUTH 质询。要予以响应,调用 RespondToAuthChallenge API 并包含以下请求参数

  • ChallengeName。使用 DEVICE_SRP_AUTH
  • ClientId。使用有效的应用程序客户端 ID。
  • ChallengeResponses。在这些响应中包含 USERNAMEDEVICE_KEYSRP_A
    注意:对于 SRP_A,使用说明中前面提到的公式。

调用此 API 后,Amazon Cognito 将以另一个质询响应:DEVICE_PASSWORD_VERIFIER。在响应中,您还将获得 ChallengeParameters SECRET_BLOCKSRP_B 的值,可供响应质询之用。

有关更多信息,请参阅请求语法您选择的 AWS 开发工具包的 API 参考

为 DEVICE_PASSWORD_VERIFIER 调用 RespondToAuthChallenge

要响应 DEVICE_PASSWORD_VERIFIER 质询,调用 RespondToAuthChallenge API 并包含以下请求参数

  • ChallengeName。使用 DEVICE_PASSWORD_VERIFIER
  • ClientId。使用有效的应用程序客户端 ID。
  • ChallengeResponses。包含 USERNAMEPASSWORD_CLAIM_SECRET_BLOCKTIMESTAMPPASSWORD_CLAIM_SIGNATUREDEVICE_KEY

定义质询响应,如下所示:

  • 对于 PASSWORD_CLAIM_SECRET_BLOCK,使用 SECRET_BLOCK 的值。
  • 对于 TIMESTAMP,包含当前时间。(例如,Tue Sep 25 00:09:40 UTC 2018。)
  • PASSWORD_CLAIM_SIGNATURE = SHA256_HMAC(K_USER, DeviceGroupKey + DeviceKey + PASSWORD_CLAIM_SECRET_BLOCK + TIMESTAMP),使用 base64 编码
  • K_USER = SHA256_HASH(S_USER)
  • S_USER = (SRP_B - k * gx)(a + ux)
  • x = SHA256_HASH(salt + FULL_PASSWORD)
  • u = SHA256_HASH(SRP_A + SRP_B)
  • k = SHA256_HASH(N + g)

从您的用户池获取 JSON Web 令牌

成功响应上一个质询后,您的 Amazon Cognito 用户池在 AuthenticationResult 中返回 JSON Web 令牌:

{ 
    "AuthenticationResult": { 
        "AccessToken": "...", 
        "ExpiresIn": 3600, 
        "IdToken": "...", 
        "RefreshToken": "...", 
        "TokenType": "Bearer" 
    }, 
    "ChallengeParameters": {} 
}

用户池身份验证流程

用户池参考(AWS 管理控制台)

AuthenticationHelper.js(AWS Amplify GitHub 存储库)

CognitoUser.js(AWS Amplify GitHub 存储库)

这篇文章对您有帮助吗?

我们可以改进什么?


需要更多帮助?