如何更改用户状态FORCE_CHANGE_PASSWORD?


97

我想使用AWS Cognito创建虚拟用户以进行测试。

然后,我使用AWS控制台创建此类用户,但是该用户的状态设置为FORCE_CHANGE_PASSWORD。使用该值,无法对该用户进行身份验证。

有没有办法更改此状态?

更新从CLI创建用户时的行为相同


1
@joe提供的用户答案
donlys

Answers:


15

抱歉,您遇到了困难。我们没有一步一步的过程,您只能创建用户并直接对其进行身份验证。我们将来可能会更改此设置,例如允许管理员设置用户直接可用的密码。目前,当您使用AdminCreateUser该应用或通过使用该应用注册用户来创建用户时,需要执行额外的步骤,要么迫使用户在登录时更改密码,要么让用户验证电子邮件或电话号码以将用户的状态更改为CONFIRMED


4
目前,当您使用AdminCreateUser或通过使用该应用程序注册用户来创建用户时,需要执行额外的步骤,要么强制用户在登录时更改密码,要么让用户验证电子邮件或电话号码以将用户状态更改为确认。这些多余的东西到底是什么,如何从JS SDK中触发它们。
萨拉·蒂瓦里

3
@joe指出,因为它已被添加,所以现在有可能。查找--permanent标志:stackoverflow.com/a/56948249/3165552
isaias-b

149

我知道已经有一段时间了,但是我认为这可能会对遇到这篇文章的其他人有所帮助。

您可以使用AWS CLI更改用户密码,但这是一个多步骤过程:


步骤1:获取所需用户的会话令牌:

aws cognito-idp admin-initiate-auth --user-pool-id %USER POOL ID% --client-id %APP CLIENT ID% --auth-flow ADMIN_NO_SRP_AUTH --auth-parameters USERNAME=%USERS USERNAME%,PASSWORD=%USERS CURRENT PASSWORD%

如果返回关于的错误Unable to verify secret hash for client,请创建另一个没有密码的应用程序客户端,并使用该客户端ID。

第2步:如果第1步成功,它将以Challenge NEW_PASSWORD_REQUIRED,其他挑战参数和用户会话密钥作为响应。然后,您可以运行第二个命令来发出质询响应:

aws cognito-idp admin-respond-to-auth-challenge --user-pool-id %USER POOL ID% --client-id %CLIENT ID% --challenge-name NEW_PASSWORD_REQUIRED --challenge-responses NEW_PASSWORD=%DESIRED PASSWORD%,USERNAME=%USERS USERNAME% --session %SESSION KEY FROM PREVIOUS COMMAND with ""%

如果您Invalid attributes given, XXX is missing在使用格式传递缺少的属性时遇到错误userAttributes.$FIELD_NAME=$VALUE

上面的命令应返回有效的身份验证结果和适当的令牌。


重要提示:为了使此工作正常进行,Cognito用户池必须具有配置了功能的App客户端ADMIN_NO_SRP_AUTH此文档中的第5步)。


24
很棒的帮助。另外两个提示:如果收到有关“无法验证客户端的秘密哈希”的错误,请创建另一个没有密码的应用程序客户端,并使用该密码(stackoverflow.com/questions/37438879/…)。如果您收到有关“给定的无效属性,XXX缺失”的错误,请使用格式userAttributes.$FIELD_NAME=$VALUEgithub.com/aws/aws-sdk-js/issues/1290)传递缺失的属性。
Lane Rettig

如果无法使用任何CLI命令(包括此答案)使用户脱离FORCE_CHANGE_PASSWORD,请尝试“ admin-disable-user”,然后“ admin-enable-user”,或使用控制台。然后,要么使用此过程,要么可以使用常规的密码重置流程。如果用户未在预定义的限制内登录到cognito,则有时用户将“过期”。(我认为默认为7天)
comfytoday

使用CLI在lambda中进行了尝试,并收到以下错误消息:给出的属性无效,名称缺失
kolodi

1
@misher由于必需的属性,您得到了它。您可以将它们包括在通话中,但语法有点怪异:--challenge-responses NEW_PASSWORD=password,USERNAME=username,userAttributes.picture=picture,userAttributes.name=name
edzillion

88

最终将其添加到AWSCLI:https ://docs.aws.amazon.com/cli/latest/reference/cognito-idp/admin-set-user-password.html

您可以使用以下方法更改用户密码并更新状态:

aws cognito-idp admin-set-user-password --user-pool-id <your user pool id> --username user1 --password password --permanent

使用此方法之前,您可能需要使用以下方法更新AWS CLI:

pip3 install awscli --upgrade


13
这是最新,最有效的解决方案!
donlys

7
这应该是答案。
年轻的

4
2020年最好,最简单的解决方案。谢谢!
都铎王朝

23

只需onSuccess: function (result) { ... },在您的登录功能内添加此代码即可。然后,您的用户将具有CONFIRMED状态。

newPasswordRequired: function(userAttributes, requiredAttributes) {
    // User was signed up by an admin and must provide new
    // password and required attributes, if any, to complete
    // authentication.

    // the api doesn't accept this field back
    delete userAttributes.email_verified;

    // unsure about this field, but I don't send this back
    delete userAttributes.phone_number_verified;

    // Get these details and call
    cognitoUser.completeNewPasswordChallenge(newPassword, userAttributes, this);
}

1
这对我有用。如果您不想更改当前密码,甚至可以输入当前密码。
mvandillen

递归FTW!谢谢!(递归是this对新密码的完全挑战)
Paul S

22

您可以FORCE_CHANGE_PASSWORD通过如下调用用户来更改该用户状态respondToAuthChallenge()

var params = {
  ChallengeName: 'NEW_PASSWORD_REQUIRED', 
  ClientId: 'your_own3j6...0obh',
  ChallengeResponses: {
    USERNAME: 'user3',
    NEW_PASSWORD: 'changed12345'
  },
  Session: 'xxxxxxxxxxZDMcRu-5u...sCvrmZb6tHY'
};

cognitoidentityserviceprovider.respondToAuthChallenge(params, function(err, data) {
  if (err) console.log(err, err.stack); // an error occurred
  else     console.log(data);           // successful response
});

之后,您会在控制台中看到user3状态为CONFIRMED


1
我不明白你怎么来的。您打了什么电话来获得XXX退出的会话?当我致电adminInitiateAuth时,出现错误消息UserNotFoundException。
Ryan Shillington

3
抱歉,如果答案不是很清楚。以下是更多详细信息:1.用户池中有一个名为“ your_own3j63rs8j16bxxxsto25db00obh”的客户端,该客户端是在没有生成密钥的情况下创建的。如果为客户端分配了密钥,则以上代码将不起作用。2)会话密钥是通过调用返回的值cognitoidentityserviceprovider.adminInitiateAuth({ AuthFlow: 'ADMIN_NO_SRP_AUTH', ClientId: 'your_own3j63rs8j16bxxxsto25db00obh', UserPoolId: 'us-east-1_DtNSUVT7n', AuthParameters: { USERNAME: 'user3', PASSWORD: 'original_password' } }, callback);
Ariel Araza

3)user3是在控制台中创建的,初始密码为'original_password'
Ariel Araza

好。我现在知道为什么我得到了UserNotFoundException。这是因为我使用别名作为用户名登录,这在JS API中可以正常工作,但显然不适用于adminInitiateAuth。谢谢Ariel Araza,感谢您的帮助。
Ryan Shillington

好极了!我终于把这个工作了。谢谢!谢谢爱丽儿!
Ryan Shillington

11

不知道您是否仍在与之抗争,但仅创建了一组测试用户,我awscli就这样使用了:

  1. 使用cognito-idp中的signup-up命令创建用户
aws cognito-idp sign-up \
   --region %aws_project_region% \
   --client-id %aws_user_pools_web_client_id% \
   --username %email_address% \
   --password %password% \
   --user-attributes Name=email,Value=%email_address%
  1. 使用admin-confirm-sign-up确认用户
aws cognito-idp admin-confirm-sign-up \
--user-pool-id %aws_user_pools_web_client_id% \
--username %email_address%

5

更新:

我现在在NodeJS Lambda中使用此代码(经过翻译放大):

// enable node-fetch polyfill for Node.js
global.fetch = require("node-fetch").default;
global.navigator = {};

const AWS = require("aws-sdk");
const cisp = new AWS.CognitoIdentityServiceProvider();

const Amplify = require("@aws-amplify/core").default;
const Auth = require("@aws-amplify/auth").default;

...


/*
  this_user: {
    given_name: string,
    password: string,
    email: string,
    cell: string
  }
*/
const create_cognito = (this_user) => {
  let this_defaults = {
    password_temp: Math.random().toString(36).slice(-8),
    password: this_user.password,
    region: global._env === "prod" ? production_region : development_region,
    UserPoolId:
      global._env === "prod"
        ? production_user_pool
        : development_user_pool,
    ClientId:
      global._env === "prod"
        ? production_client_id
        : development_client_id,
    given_name: this_user.given_name,
    email: this_user.email,
    cell: this_user.cell,
  };

  // configure Amplify
  Amplify.configure({
    Auth: {
      region: this_defaults.region,
      userPoolId: this_defaults.UserPoolId,
      userPoolWebClientId: this_defaults.ClientId,
    },
  });
  if (!Auth.configure())
    return Promise.reject("could not configure amplify");

  return new Promise((resolve, reject) => {
    let _result = {};

    let this_account = undefined;
    let this_account_details = undefined;

    // create cognito account
    cisp
      .adminCreateUser({
        UserPoolId: this_defaults.UserPoolId,
        Username: this_defaults.given_name,
        DesiredDeliveryMediums: ["EMAIL"],
        ForceAliasCreation: false,
        MessageAction: "SUPPRESS",
        TemporaryPassword: this_defaults.password_temp,
        UserAttributes: [
          { Name: "given_name", Value: this_defaults.given_name },
          { Name: "email", Value: this_defaults.email },
          { Name: "phone_number", Value: this_defaults.cell },
          { Name: "email_verified", Value: "true" },
        ],
      })
      .promise()
      .then((user) => {
        console.warn(".. create_cognito: create..");
        _result.username = user.User.Username;
        _result.temporaryPassword = this_defaults.password_temp;
        _result.password = this_defaults.password;

        // sign into cognito account
        return Auth.signIn(_result.username, _result.temporaryPassword);
      })
      .then((user) => {
        console.warn(".. create_cognito: signin..");

        // complete challenge
        return Auth.completeNewPassword(user, _result.password, {
          email: this_defaults.email,
          phone_number: this_defaults.cell,
        });
      })
      .then((user) => {
        console.warn(".. create_cognito: confirmed..");
        this_account = user;
        // get details
        return Auth.currentAuthenticatedUser();
      })
      .then((this_details) => {
        if (!(this_details && this_details.attributes))
          throw "account creation failes";

        this_account_details = Object.assign({}, this_details.attributes);

        // signout
        return this_account.signOut();
      })
      .then(() => {
        console.warn(".. create_cognito: complete");
        resolve(this_account_details);
      })
      .catch((err) => {
        console.error(".. create_cognito: error");
        console.error(err);
        reject(err);
      });
  });
};

我正在设置一个临时密码,然后将其重置为用户请求的密码。

旧帖子:

您可以使用amazon-cognito-identity-js SDK解决此问题,方法是:在创建帐户后,使用临时密码进行身份验证cognitoidentityserviceprovider.adminCreateUser(),然后cognitoUser.completeNewPasswordChallenge()cognitoUser.authenticateUser( ,{newPasswordRequired})创建用户的函数内部运行-。

我在AWS lambda中使用以下代码来创建启用的Cognito用户帐户。我相信它可以优化,请耐心等待。这是我的第一篇文章,对JavaScript还是很陌生。

var AWS = require("aws-sdk");
var AWSCognito = require("amazon-cognito-identity-js");

var params = {
    UserPoolId: your_poolId,
    Username: your_username,
    DesiredDeliveryMediums: ["EMAIL"],
    ForceAliasCreation: false,
    MessageAction: "SUPPRESS",
    TemporaryPassword: your_temporaryPassword,
    UserAttributes: [
        { Name: "given_name", Value: your_given_name },
        { Name: "email", Value: your_email },
        { Name: "phone_number", Value: your_phone_number },
        { Name: "email_verified", Value: "true" }
    ]
};

var cognitoidentityserviceprovider = new AWS.CognitoIdentityServiceProvider();
let promise = new Promise((resolve, reject) => {
    cognitoidentityserviceprovider.adminCreateUser(params, function(err, data) {
        if (err) {
            reject(err);
        } else {
            resolve(data);
        }
    });
});

promise
    .then(data => {
        // login as new user and completeNewPasswordChallenge
        var anotherPromise = new Promise((resolve, reject) => {
            var authenticationDetails = new AWSCognito.AuthenticationDetails({
                Username: your_username,
                Password: your_temporaryPassword
            });
            var poolData = {
                UserPoolId: your_poolId,
                ClientId: your_clientId
            };
            var userPool = new AWSCognito.CognitoUserPool(poolData);
            var userData = {
                Username: your_username,
                Pool: userPool
            };

            var cognitoUser = new AWSCognito.CognitoUser(userData);
            let finalPromise = new Promise((resolve, reject) => {
                cognitoUser.authenticateUser(authenticationDetails, {
                    onSuccess: function(authResult) {
                        cognitoUser.getSession(function(err) {
                            if (err) {
                            } else {
                                cognitoUser.getUserAttributes(function(
                                    err,
                                    attResult
                                ) {
                                    if (err) {
                                    } else {
                                        resolve(authResult);
                                    }
                                });
                            }
                        });
                    },
                    onFailure: function(err) {
                        reject(err);
                    },
                    newPasswordRequired(userAttributes, []) {
                        delete userAttributes.email_verified;
                        cognitoUser.completeNewPasswordChallenge(
                            your_newPoassword,
                            userAttributes,
                            this
                        );
                    }
                });
            });

            finalPromise
                .then(finalResult => {
                    // signout
                    cognitoUser.signOut();
                    // further action, e.g. email to new user
                    resolve(finalResult);
                })
                .catch(err => {
                    reject(err);
                });
        });
        return anotherPromise;
    })
    .then(() => {
        resolve(finalResult);
    })
    .catch(err => {
        reject({ statusCode: 406, error: err });
    });

@Tom-它对您有用吗?有什么我可以澄清的吗?
qqan.ny

现在好多了。
汤姆·阿兰达

@ qqan.ny同时使用promise和回调?为什么?
Iurii Golskyi

@Iurii Golskyi-那时我并不了解,它才刚刚从头开始学习AWS和JS。
qqan.ny,

4

对于Java SDK,假设您已设置Cognito客户端,并且您的用户处于FORCE_CHANGE_PASSWORD状态,则可以执行以下操作以使用户CONFIRMED ...然后正常进行身份验证。

AdminCreateUserResult createUserResult = COGNITO_CLIENT.adminCreateUser(createUserRequest());

AdminInitiateAuthResult authResult = COGNITO_CLIENT.adminInitiateAuth(authUserRequest());


Map<String,String> challengeResponses = new HashMap<>();
challengeResponses.put("USERNAME", USERNAME);
challengeResponses.put("NEW_PASSWORD", PASSWORD);
RespondToAuthChallengeRequest respondToAuthChallengeRequest = new RespondToAuthChallengeRequest()
      .withChallengeName("NEW_PASSWORD_REQUIRED")
      .withClientId(CLIENT_ID)
      .withChallengeResponses(challengeResponses)
      .withSession(authResult.getSession());

COGNITO_CLIENT.respondToAuthChallenge(respondToAuthChallengeRequest);

希望它对那些集成测试有所帮助(对格式感到抱歉)


4

基本上,这是相同的答案,但对于.Net C#SDK:

以下将使用所需的用户名和密码进行完整的管理员用户创建。具有以下用户模型:

public class User
{
    public string Username { get; set; }
    public string Password { get; set; }
}

您可以使用以下方法创建用户并使其可供使用:

   public void AddUser(User user)
    {
        var tempPassword = "ANY";
        var request = new AdminCreateUserRequest()
        {
            Username = user.Username,
            UserPoolId = "MyuserPoolId",
            TemporaryPassword = tempPassword
        };
        var result = _cognitoClient.AdminCreateUserAsync(request).Result;
        var authResponse = _cognitoClient.AdminInitiateAuthAsync(new AdminInitiateAuthRequest()
        {
            UserPoolId = "MyuserPoolId",
            ClientId = "MyClientId",
            AuthFlow = AuthFlowType.ADMIN_NO_SRP_AUTH,
            AuthParameters = new Dictionary<string, string>()
            {
                {"USERNAME",user.Username },
                {"PASSWORD", tempPassword}
            }
        }).Result;
        _cognitoClient.RespondToAuthChallengeAsync(new RespondToAuthChallengeRequest()
        {
         ClientId = "MyClientId",
            ChallengeName = ChallengeNameType.NEW_PASSWORD_REQUIRED,
            ChallengeResponses = new Dictionary<string, string>()
            {
                {"USERNAME",user.Username },
                {"NEW_PASSWORD",user.Password }
            },
            Session = authResponse.Session
        });
    }

3

如果您尝试从控制台以管理员身份更改状态。创建用户后,请按照以下步骤操作。

  1. 在Cognito转到->“管理用户池”->
  2. 转到“应用程序集成”部分下的“应用程序客户端设置”。
  3. 检查以下各项:i)Cognito用户池ii)授权码授予iii)隐式授予iv)电话v)电子邮件vi)openid vii)aws.cognito.signin.user.admin viii)个人资料
  4. 输入您的应用程序的回调URL。如果不确定,请输入例如:https : //google.com,然后再将其更改为实际的回调URL
  5. 点击保存更改。
  6. 保存更改后,单击链接“启动托管的用户界面”
  7. 输入新创建的用户的凭据
  8. 使用新凭据重置密码并将其共享给用户

第2步

步骤3 4 5 6

步骤7

步骤8


2

我知道这是相同的答案,但认为这可能对Go开发人员社区有所帮助。基本上是发起身份验证请求,获取会话并响应挑战NEW_PASSWORD_REQUIRED

func sessionWithDefaultRegion(region string) *session.Session {
    sess := Session.Copy()
    if v := aws.StringValue(sess.Config.Region); len(v) == 0 {
        sess.Config.Region = aws.String(region)
    }

    return sess
}



func (c *CognitoAppClient) ChangePassword(userName, currentPassword, newPassword string)   error {

    sess := sessionWithDefaultRegion(c.Region)
    svc := cognitoidentityprovider.New(sess)

    auth, err := svc.AdminInitiateAuth(&cognitoidentityprovider.AdminInitiateAuthInput{
        UserPoolId:aws.String(c.UserPoolID),
        ClientId:aws.String(c.ClientID),
        AuthFlow:aws.String("ADMIN_NO_SRP_AUTH"),
        AuthParameters: map[string]*string{
            "USERNAME": aws.String(userName),
            "PASSWORD": aws.String(currentPassword),
        },

    })



    if err != nil {
        return err
    }

    request := &cognitoidentityprovider.AdminRespondToAuthChallengeInput{
        ChallengeName: aws.String("NEW_PASSWORD_REQUIRED"),
        ClientId:aws.String(c.ClientID),
        UserPoolId: aws.String(c.UserPoolID),
        ChallengeResponses:map[string]*string{
            "USERNAME":aws.String(userName),
            "NEW_PASSWORD": aws.String(newPassword),
        },
        Session:auth.Session,
    }


    _, err = svc.AdminRespondToAuthChallenge(request)

    return err 
}

这是一个单元测试:

import (
    "fmt"
    "github.com/aws/aws-sdk-go/service/cognitoidentityprovider"
    . "github.com/smartystreets/goconvey/convey"
    "testing"
)


func TestCognitoAppClient_ChangePassword(t *testing.T) {


    Convey("Testing ChangePassword!", t, func() {
        err := client.ChangePassword("user_name_here", "current_pass", "new_pass")



        Convey("Testing ChangePassword Results!", func() {
            So(err, ShouldBeNil)

        })

    })
}

1

好。我终于有了代码,管理员可以在其中创建新用户。过程如下:

  1. 管理员创建用户
  2. 用户收到一封包含其临时密码的电子邮件
  3. 用户登录并要求更改密码

步骤1是困难的部分。这是我在Node JS中创建用户的代码:

let params = {
  UserPoolId: "@cognito_pool_id@",
  Username: username,
  DesiredDeliveryMediums: ["EMAIL"],
  ForceAliasCreation: false,
  UserAttributes: [
    { Name: "given_name", Value: firstName },
    { Name: "family_name", Value: lastName},
    { Name: "name", Value: firstName + " " + lastName},
    { Name: "email", Value: email},
    { Name: "custom:title", Value: title},
    { Name: "custom:company", Value: company + ""}
  ],
};
let cognitoIdentityServiceProvider = new AWS.CognitoIdentityServiceProvider();
cognitoIdentityServiceProvider.adminCreateUser(params, function(error, data) {
  if (error) {
    console.log("Error adding user to cognito: " + error, error.stack);
    reject(error);
  } else {
    // Uncomment for interesting but verbose logging...
    //console.log("Received back from cognito: " + CommonUtils.stringify(data));
    cognitoIdentityServiceProvider.adminUpdateUserAttributes({
      UserAttributes: [{
        Name: "email_verified",
        Value: "true"
      }],
      UserPoolId: "@cognito_pool_id@",
      Username: username
    }, function(err) {
      if (err) {
        console.log(err, err.stack);
      } else {
        console.log("Success!");
        resolve(data);
      }
    });
  }
});

基本上,您需要发送第二条命令以强制将电子邮件视为已验证。用户仍然需要转到其电子邮件以获取临时密码(该密码也将验证电子邮件)。但是如果没有第二次呼叫将电子邮件设置为经过验证,您将无法获得正确的呼叫以重置其密码。


我仍然没有收到电子邮件,有什么建议吗?
Vinicius

很奇怪,您是否已在Cognito中正确设置了电子邮件地址,并且可以访问SES等?在您验证要发送给的电子邮件地址或获得批准发送给任何人之前,Cogntio不仅会向他人发送电子邮件。
瑞安·希灵顿

我收到确认码电子邮件,因此设置正确。只是带有临时密码的电子邮件永远不会出现...我最终创建了一个lambda附加到预注册触发器上以发送电子邮件。
Vinicius
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.