有啥方法可以在 AWS Lambda 中获取 Cognito 用户名?

Posted

技术标签:

【中文标题】有啥方法可以在 AWS Lambda 中获取 Cognito 用户名?【英文标题】:Is there any way to get the Cognito username in AWS Lambda?有什么方法可以在 AWS Lambda 中获取 Cognito 用户名? 【发布时间】:2017-07-10 15:25:57 【问题描述】:

据我所知,AWS Lambda 函数无法查找我的 Cognito 用户的用户名(我正在使用 UserPools)。

这似乎非常奇怪,因为我认为到处都是应用程序几乎总是依赖于操作用户名。

我已成功获得 Cognito IdentityId,但我看不到任何方法可以将 IdentityId 与查找 IdentityId 相关的 Cognito 用户的任何内容相关联。

有没有办法获取用户名? IdentityId和用户名是什么关系?

【问题讨论】:

你解决过这个问题吗????让我知道我提供的解决方案是否对您有帮助,我在每个项目中都使用它,如果有的话,如果能获得一些关于它如何为其他人工作的反馈会很酷。 @lopezdp 那个项目是 3 年前我真的不记得了。 【参考方案1】:

一段时间以来,我一直在努力寻找这个问题的答案,因为在线上的任何这些线程都没有任何简明的回答。

在用户使用自定义属性针对您的 Cognito 用户池拥有 Authenticated 凭据后,您似乎正在尝试提出有效的 Authorization 策略。

我创建了一个库,用于导出一些函数,这些函数允许我为 authenticated 用户捕获 UserPoolIdUsername,以便我可以捕获 custom:<attribute> 我需要在我的 lambda 中,以便我已实现的条件可以将 API 用于我需要为我的应用身份验证的每个用户提供授权的其余 AWS 服务。

这是我的图书馆:

import AWS from "aws-sdk";
// ensure correct AWS region is set
AWS.config.update(
    region: "us-east-2"
);

// function will parse the user pool id from a string
export function parseUserPoolId(str) 
    let regex = /[^[/]+(?=,)/g;
    let match = regex.exec(str)[0].toString();

    console.log("Here is the user pool id: ", match);

    return match.toString();


// function will parse the username from a string
export function parseUserName(str) 
    let regex = /[a-z,A-Z,0-9,-]+(?![^:]*:)/g;
    let match = regex.exec(str)[0].toString();

    console.log("Here is the username: ", match);

    return match.toString();


// function retries UserAttributes array from cognito
export function getCustomUserAttributes(upid, un) 
    // instantiate the cognito IdP
    const cognito = new AWS.CognitoIdentityServiceProvider(
        apiVersion: "2016-04-18"
    );

    const params = 
        UserPoolId: upid,
        Username: un
    ;

    console.log("UserPoolId....: ", params.UserPoolId);
    console.log("Username....: ", params.Username);

    try 
        const getUser = cognito.adminGetUser(params).promise();
        console.log("GET USER....: ", getUser);
        // return all of the attributes from cognito
        return getUser;
     catch (err) 
        console.log("ERROR in getCustomUserAttributes....: ", err.message);
        return err;
    

实现了这个库后,它现在可以被您需要为其创建授权策略的任何 lambda 使用。

在你的 lambda 中,你需要导入上面的库(我省略了下面的导入语句,你需要添加它们以便访问导出的函数),你可以这样实现它们的使用::

export async function main(event, context) 
  const upId = parseUserPoolId(
    event.requestContext.identity.cognitoAuthenticationProvider
  );
  // Step 2 --> Get the UserName from the requestContext
  const usrnm = parseUserName(
    event.requestContext.identity.cognitoAuthenticationProvider
  );
  // Request body is passed to a json encoded string in
  // the 'event.body'
  const data = JSON.parse(event.body);

  try 
    // TODO: Make separate lambda for AUTHORIZATION
    let res = await getCustomUserAttributes(upId, usrnm);

    console.log("THIS IS THE custom:primaryAccountId: ", res.UserAttributes[4].Value);
    console.log("THIS IS THE custom:ROLE: ", res.UserAttributes[3].Value);
    console.log("THIS IS THE custom:userName: ", res.UserAttributes[1].Value);

    const primaryAccountId = res.UserAttributes[4].Value;

   catch (err) 
    // eslint-disable-next-line
    console.log("This call failed to getattributes");
    return failure(
      status: false
    );
  



来自 Cognito 的响应将提供一个包含您需要的自定义属性的数组。 Console.log 使用 console.log("THIS IS THE Cognito response: ", res.UserAttributes); 记录来自 Cognito 的响应,并检查 CloudWatch 日志中所需属性的索引号并调整所需的索引:

res.UserAttributes[n]

现在您有一个authorization 机制,您可以在 lambda 中使用该机制以允许用户发布到 DynamoDB,或使用您的应用程序中的任何其他 AWS 服务,并为每个经过身份验证的用户提供正确的授权。

在您可以在 res.UserAttributes[n] 中看到的响应中,您将看到 sub 的属性,这是您正在寻找的。​​p>

【讨论】:

parseUserName 给了我 'sub' uuid,它不允许我使用 getAdminUser 获取用户。 (getCustomUserAttributes 中的错误......:用户不存在。)我错过了一些设置吗? @pivu0 是的,您错过了解决方案的其余部分。你必须看代码的后半部分才能看到我如何使用它们,代码的前半部分是所需的不同功能。注意我如何使用它:await getCustomUserAttributes(upId, usrnm); 此外,如果用户不存在,也许你应该在你的 Cognito 实例中创建/注册一个用户。这将与已经注册的用户一起使用,以便您可以获得所需的自定义属性... @pivu0 您需要将带有该子数据的 paras 对象传递到:cognito.adminGetUser(params).promise(); 我没有遗漏任何东西,并按照您的说明实施。是 cognito.adminGetUser(params).promise() 引发了这个错误。用户已注册,如果我使用实际用户名(我将用户名硬编码以进行测试)而不是 sub 我会找到它。无论如何,我在某个地方发现,如果我使用联合身份,您将无法找到仅使用 sub 的用户。【参考方案2】:

您可以从 Authorization 标头中获取 JWT 令牌,然后使用您的语言的某些库对其进行解码。

在 JWT 的负载中是用户名。

或者您可以在CognitoIdentityServiceProvider (http://docs.aws.amazon.com/AWSjavascriptSDK/latest/AWS/CognitoIdentityServiceProvider.html#listUsers-property) 上调用listUsers,使用您在...authorizer.claims.sub 中获得的sub 的过滤器。

【讨论】:

我需要在后端得到这个。你的建议可以在后端完成吗? @DukeDougal 我的建议是后端。查看后端的 Authorization 标头。它是一个编码的 JWT 令牌,您可以对其进行解码和查看。包含有用的数据。 同意授权标头。使用过滤器调用 listUsers 似乎不能很好地扩展。【参考方案3】:

在 Api 网关中添加 Cognito Authorizer 后,我在 lambda 中获取了用户详细信息,它在 event.requestContext.authorizer.claims 对象的标头中传递了解码的 Authorization 令牌。

【讨论】:

就是这样。【参考方案4】:

详细说明@doorstuck 的回答,如果您使用的是 APIG 调用的 Lambda 和 AWS_IAM 授权。然后就可以得到用户名等属性如下:

event.requestContext.identity.cognitoAuthenticationProvider 是一个字符串,看起来像

“cognito-idp.ap-northeast-1.amazonaws.com/ap-northeast-1_xxxxxxx,cognito-idp.ap-northeast-1.amazonaws.com/ap-northeast-1_xxxxxx:CognitoSignIn:SSSSSSSS”

SSSSSSSS 是用户池中用户的子用户。您可以轻松解码字符串以获取 sub 并在 listUsers 的过滤器中使用它。

例子:

const provider = 
event.requestContext.identity.cognitoAuthenticationProvider;
const sub=provider.split(':')[2];
const Params = 
     UserPoolId: 'xxxxxxxxx', /* required */
     Filter: "sub=\""+ sub + "\"",
     Limit: 1
;
cognitoidentityserviceprovider.listUsers(Params, function(err, data) 
      if (err) console.log(err, err.stack); // an error occurred
      else   console.log(data.Users[0].Attributes);       
);

数据包括有关返回用户的有用信息,其中 data.Users[0].Attributes 包含您的所有用户属性。 结果是

[  Username: 'xxxxx',
Attributes: [Object],
UserCreateDate: 2017-09-12T04:52:50.589Z,
UserLastModifiedDate: 2017-10-24T01:50:00.109Z,
Enabled: true,
UserStatus: 'CONFIRMED'  ] 

data.Users[0].Attributes 是

[  Name: 'sub', Value: 'SSSSSSS' ,
 Name: 'address', Value: 'xxxxxxxxi' ,
 Name: 'email_verified', Value: 'true' ,
..... ]

注意,你也可以使用过滤返回的属性

AttributesToGet: [
    'STRING_VALUE',
    /* more items */
  ],

在参数中。

【讨论】:

listUsers 调用不会根据每个请求查询整个用户群吗?我不确定这将如何扩展。【参考方案5】:

如果您将 Lambda 函数与 API 网关一起使用,您可以使用 Cognito Authorizer 直接对您的用户池令牌进行身份验证,并通过 $context.authorizer.claims.preferred_username 传入从令牌中提取的用户名

有关此集成的更多详细信息在这里:http://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-integrate-with-cognito.html

【讨论】:

【参考方案6】:

我们也可以在身体映射模板中操作上下文来获取子(用户名),它对我来说很好用。试试这个,而不是拆分你的 lamda 函数。

 #set($sub = $context.identity.cognitoAuthenticationProvider.split(':')[2])

"tenantId": "$sub"
 

【讨论】:

在尝试了各种方法之后 - 这对我有用 - 在 python zappa from flask import request request.environ.get('lambda.event').get('requestContext').get('identity').get('cognitoAuthenticationProvider') cognito-idp.us-east-1.amazonaws.com/us-east-xxxxxxxx,cognito-idp.us-east-1.amazonaws.com/us-east-xxxxxx:CognitoSignIn:xxxxxxx-86d4-4cb0-bedb-xxxx 最后一位是登录的 cognito 用户的用户名

以上是关于有啥方法可以在 AWS Lambda 中获取 Cognito 用户名?的主要内容,如果未能解决你的问题,请参考以下文章

AWS - 在 SNS 订阅或 Lambda 函数上设置死信队列有啥区别?

AWS Lambda超时时获取通知

我的 AWS Lambda 函数有啥问题?

在 aws lambda 中获取请求参数

AWS CloudFormation:如何从另一个AWS账户为Lambda代码指定存储桶?

如何通过在 AWS CLI 中使用其 ARN 来获取 lambda 函数?