没有密码的 AWS Cognito 用户池

Posted

技术标签:

【中文标题】没有密码的 AWS Cognito 用户池【英文标题】:AWS Cognito User Pool without a password 【发布时间】:2018-01-21 20:04:17 【问题描述】:

我想使用电话号码作为我的应用程序的用户名,并且我希望能够通过每次他们想要登录时验证电话号码来简化注册 - 没有混乱的密码记住业务。

如何使用 AWS Cognito 用户池执行此操作,因为它要求我强制为每个用户配置密码。

我想为每个用户使用一个虚拟密码并配置强制用户验证。每次用户退出时,我都可以“取消验证”用户,以便下次自动要求他们验证电话号码。此外,如果用户经过验证,我会将我的应用程序连接到仅“登录”。

如果这是最好的方法,请告诉我:(我是 AWS 新手,我找不到任何适合这种情况的帖子。

谢谢!!

【问题讨论】:

最近亚马逊出一个解决方案:aws.amazon.com/blogs/mobile/… 【参考方案1】:

由于 AWS Cognito 当前不支持无密码身份验证,因此您需要使用存储在外部的随机密码来实施解决方法。您可以按如下方式实现身份验证流程。

用户注册后(还要求提供手机号码并强制填写),将手机号码、用户名和密码也存储在使用AWS KMS 加密的 Dynamodb 中(以提高安全性)。 您可以使用MFA与手机号码进行身份验证挑战,以便用户输入手机号码并按登录后(在前端),在后端您可以自动进行用户名密码匹配(Passthrough)并触发MFA发送代码用于用户的移动设备并使用 AWS Cognito 开发工具包进行验证(不实施自定义移动消息和质询)。 如果您计划手动实施流程(无 MFA)以发送 SMS 和验证,您可以使用 AWS SNS。

查看以下代码示例以了解 MFA 的见解,并参考 this link 了解更多详细信息。

    var userData =  
        Username : 'username',
        Pool : userPool
    ;

    cognitoUser = new AWSCognito.CognitoIdentityServiceProvider.CognitoUser(userData);

    var authenticationData = 
        Username : 'username',
        Password : 'password',
    ;

    var authenticationDetails = new AWSCognito.CognitoIdentityServiceProvider.AuthenticationDetails(authenticationData);

    cognitoUser.authenticateUser(authenticationDetails, 
        onSuccess: function (result) 
            alert('authentication successful!')
        ,

        onFailure: function(err) 
            alert(err);
        ,

        mfaRequired: function(codeDeliveryDetails) 
            var verificationCode = prompt('Please input verification code' ,'');
            cognitoUser.sendMFACode(verificationCode, this);
        

    );

注意:此处带有手机号码的 MFA 并非用于 MFA 的目的,而是作为一种解决方法以满足您的要求。

【讨论】:

非常感谢阿山。这回答了我的问题:) 将每个用户的唯一随机密码存储在外部数据库中,而不是只为所有用户使用一个秘密虚拟密码,有什么安全优势? 我遇到了这样一种情况:getsession 发送 OTP,然后委托调用我不知道调用哪个函数来设置接收到的 OTP 并再次获取令牌。 这取自以下文章:aws.amazon.com/blogs/mobile/…【参考方案2】:

这与 OP 要求的内容略有不同,因为它使用单个密钥,但我认为它可能会帮助其他解决这个问题的人。

我能够通过为 Cognito 触发器创建自定义 lambda 来做到这一点:定义身份验证挑战、创建身份验证挑战和验证身份验证挑战。

我的要求是我希望我的后端使用 secret 然后为任何 Cognito 用户获取访问和刷新令牌。

定义身份验证挑战 Lambda

exports.handler = async event => 
  if (
    event.request.session &&
    event.request.session.length >= 3 &&
    event.request.session.slice(-1)[0].challengeResult === false
  ) 
    // The user provided a wrong answer 3 times; fail auth
    event.response.issueTokens = false;
    event.response.failAuthentication = true;
   else if (
    event.request.session &&
    event.request.session.length &&
    event.request.session.slice(-1)[0].challengeResult === true
  ) 
    // The user provided the right answer; succeed auth
    event.response.issueTokens = true;
    event.response.failAuthentication = false;
   else 
    // The user did not provide a correct answer yet; present challenge
    event.response.issueTokens = false;
    event.response.failAuthentication = false;
    event.response.challengeName = 'CUSTOM_CHALLENGE';
  
  return event;
;

创建身份验证挑战 Lambda

exports.handler = async event => 
  if (event.request.challengeName == 'CUSTOM_CHALLENGE') 
    // The value set for publicChallengeParameters is arbitrary for our
    // purposes, but something must be set
    event.response.publicChallengeParameters =  foo: 'bar' ;
  
  return event;
;

验证身份验证挑战 Lambda

exports.handler = async event => 
  if (event.request.challengeName == 'CUSTOM_CHALLENGE') 
    // The value set for publicChallengeParameters is arbitrary for our
    // purposes, but something must be set
    event.response.publicChallengeParameters =  foo: 'bar' ;
  
  return event;
;

然后我可以使用一些 JS,使用 amazon-cognito-identity-js,来提供秘密并获取令牌:

var authenticationData = 
  Username : 'username'
;
var authenticationDetails = new AmazonCognitoIdentity.AuthenticationDetails(authenticationData);
var poolData = 
  UserPoolId : '...', // Your user pool id here
  ClientId : '...' // Your client id here
;
var userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);
var userData = 
  Username : 'username',
  Pool : userPool
;
var cognitoUser = new AmazonCognitoIdentity.CognitoUser(userData);

cognitoUser.setAuthenticationFlowType('CUSTOM_AUTH');

cognitoUser.initiateAuth(authenticationDetails, 
  onSuccess: function(result) 
    // User authentication was successful
  ,
  onFailure: function(err) 
    // User authentication was not successful
  ,
  customChallenge: function(challengeParameters) 
    // User authentication depends on challenge response
    var challengeResponses = 'secret'
    cognitoUser.sendCustomChallengeAnswer(challengeResponses, this);
  
);

【讨论】:

这对我正在处理的需求最有用。欣赏详细的见解。【参考方案3】:

这可能有效,但考虑到安全性,将密码存储在 dynamoDB 中可能会出现问题。相反,我们可以这样尝试:

选项#1:- 用户使用用户名和密码注册。

    设置认知触发器 - 我们可以使用 lambda 函数。 A.创建身份验证挑战 B. 定义身份验证挑战 C. 验证身份验证挑战响应 客户端应用应实现 CUSTOM_CHALLENGE 身份验证流程。 要求用户输入注册的电话号码,在用户名字段中传递。触发器 B 将了解请求并将流程传递给触发器 A,触发器 A 将生成随机码 5. 使用 AWS SNS 服务向用户手机号码发送短信 触发器 C 将验证 OTP 并允许登录 需要考虑的要点: 一种。将电话号码设置为别名(选择还允许使用经过验证的电话号码登录) 湾。将电话号码字段设为可验证(这允许用户接收 OTP)

选项#1:- 用户无需用户名和密码即可注册。 认知设置

    将电话号码设置为别名(选择还允许使用经过验证的电话号码登录) 将电话号码字段设为可验证(这允许用户接收 OTP) 在注册过程中不要要求用户提供用户名和密码,只需询问电话号码 为用户名和密码生成唯一的 UUID,并将它们与电话号码一起传递给 cognito Cognito 向用户发送 OTP 代码以确认帐户。 对于具有 OTP 登录设置触发器的电话号码,如上述选项中所述。

有关触发器代码,请参阅 aws cognito pool with multiple sign in options

【讨论】:

以上是关于没有密码的 AWS Cognito 用户池的主要内容,如果未能解决你的问题,请参考以下文章

将用户从 cognito 用户池迁移到身份池

AWS CloudFormation 脚本失败 - 不允许 Cognito 使用您的电子邮件身份

AWS Cognito 用户池 + 用于身份验证/登录的社交提供商

AWS Cognito - 重置用户 MFA

AWS cognito 用户迁移池触发器不适用于登录流程

AWS Cognito 用户池应用程序客户端中的设置意味着啥