在 DotNet 中创建 AWS Cognito PreSignup Lambda

Posted

技术标签:

【中文标题】在 DotNet 中创建 AWS Cognito PreSignup Lambda【英文标题】:Creating a AWS Cognito PreSignup Lambda in DotNet 【发布时间】:2017-10-24 03:08:31 【问题描述】:

使用 .Net Core 1.0 Lambda 我希望能够创建一个 Lambda 函数来处理来自 AWS Cognito 用户池的 PreSignUp 触发器。

using Amazon.Lambda.Core;

[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))]

public class PreSignUp_SignUp

  public string userPoolId  get; set; 
  public const string EmailKey = "email";
  public const string PhoneNumber = "phone_number";
  public Dictionary<string,string> userAttributes  get; set; 
  public Dictionary<string, string> validationData  get; set; 


public class PreSignup_SignUpResponse

  public bool autoConfirmUser  get; set; 


public class Function

  public PreSignup_SignUpResponse FunctionHandler(PreSignUp_SignUp input, ILambdaContext context)
  
      return new PreSignup_SignUpResponse  autoConfirmUser = true ;
  

虽然请求成功并在调用 Lambda 时返回响应,但示例请求如下:


  "datasetName": "datasetName",
  "eventType": "SyncTrigger",
  "region": "us-east-1",
  "identityId": "identityId",
  "datasetRecords": 
    "SampleKey2": 
      "newValue": "newValue2",
      "oldValue": "oldValue2",
      "op": "replace"
    ,
    "SampleKey1": 
      "newValue": "newValue1",
      "oldValue": "oldValue1",
      "op": "replace"
    
  ,
  "identityPoolId": "identityPoolId",
  "version": 2

通过 .Net AmazonCognitoIdentityProviderClient 执行实际注册时,我收到错误消息:

Amazon.CognitoIdentityProvider.Model.InvalidLambdaResponseException : 无法识别的 lambda 输出

我猜这意味着我没有得到正确的响应(甚至可能是请求)的形状。

是否有人提供适用于 AWS Cognito 中 PreSignUp 触发器的 .Net Lambda 函数示例?

【问题讨论】:

【参考方案1】:

认知触发器请求/响应必须包含认知触发器文档中指定的整个有效负载:

http://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-identity-pools-working-with-aws-lambda-triggers.html

在诊断此问题时,我发现最好的起点是创建一个函数处理程序,该处理程序接受一个 JObject,然后记录并返回相同的对象,例如

public JObject FunctionHandler(JObject input, ILambdaContext context)

    context.Logger.LogLine("Input was: " + input);
    return input;

这会在 cloudwatch 日志中捕获有效负载,然后帮助引导您实现所需的强类型结构化。

在我的 PreSignUp 案例中,我最终创建了以下类型来创建一个简单的函数,该函数可以自动验证所有提供的凭据。

public abstract class AbstractTriggerRequest

    [JsonProperty("userAttributes")]
    public Dictionary<string, string> UserAttributes  get; set; 


public abstract class AbstractTriggerResponse



public class TriggerCallerContext

    [JsonProperty("awsSdkVersion")]
    public string AwsSdkVersion  get; set; 
    [JsonProperty("clientId")]
    public string ClientId  get; set; 


public abstract class AbstractTriggerBase<TRequest, TResponse>
    where TRequest: AbstractTriggerRequest
    where TResponse: AbstractTriggerResponse

    [JsonProperty("version")]
    public int Version  get; set; 
    [JsonProperty("triggerSource")]
    public string TriggerSource  get; set; 
    [JsonProperty("region")]
    public string Region  get; set; 
    [JsonProperty("userPoolId")]
    public string UserPoolId  get; set;   
    [JsonProperty("callerContext")]
    public TriggerCallerContext CallerContext  get; set; 
    [JsonProperty("request")]
    public TRequest Request  get; set; 
    [JsonProperty("response")]
    public TResponse Response  get; set; 
    [JsonProperty("userName", NullValueHandling = NullValueHandling.Ignore)]
    public string UserName  get; set; 


public class PreSignUpSignUpRequest : AbstractTriggerRequest

    [JsonProperty("validationData")]
    public Dictionary<string,string> ValidationData  get; set; 

然后,Lambda 函数以以下签名结束:

public class Function

    public PreSignUp_SignUp FunctionHandler(PreSignUp_SignUp input, ILambdaContext context)
    
        context.Logger.LogLine("Auto-confirming everything!");

        input.Response = new PreSignUpSignUpResponse 
            AutoConfirmUser = true,
            // you can only auto-verify email or phone if it's present in the user attributes
            AutoVerifyEmail = input.Request.UserAttributes.ContainsKey("email"),
            AutoVerifyPhone = input.Request.UserAttributes.ContainsKey("phone_number") 
        ;

        return input;
    

希望这可以帮助其他在为 Cognito 编写 Lambda 触发器时遇到问题的人。

【讨论】:

这是一个很好的答案,但也请查看 DaddyCoder 对 .netcore 3.1 应用程序语法更新的响应,因为您可能会使用新的 JSON 序列化程序【参考方案2】:

除非您仍然使用旧的、性能较低的 Amazon.Lambda.Serialization.Json.JsonSerializer,否则之前的两个响应现在不准确。这个旧的序列化程序使用Newtonsoft.Json,而新的Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer 实现了最近的System.Text.Json

因此,JObject 参数不再适用,而应替换为 JsonElement。如果你尝试将JObject 与这个新的序列化程序一起使用,你会得到一个错误,因为序列化程序不知道如何处理这个对象。

您应该阅读this 以更好地了解它的工作原理,但您可以使用GetProperty("[insert property name here]") 访问JsonElement 的属性。

例如:

public async Task<JsonElement> FunctionHandler(JsonElement input, ILambdaContext context)

    var request = input.GetProperty("request");
    var userAttributes = request.GetProperty("userAttributes");
    string email = userAttributes.GetProperty("email").GetString();

    return input;

这样,您无需构建整个类来容纳所需的请求和响应参数,只需获取和设置您需要的属性即可。

【讨论】:

这是正确的。 JsonElement 类也可以很好地记录日志,因此按照 Bittercoder 推荐的记录输入的起点,您仍然可以使用以下语法:context.Logger.LogLine("Input was: " + input); 查看 Cloudwatch 日志中的请求负载。【参考方案3】:

这里已经有另一个很好的答案了。不过我不是 .NET 开发专家,所以这个解决方案对我来说更有意义。

class AutoVerifyEmail

    public AutoVerifyEmail()  

    public JObject AutoVerifyEmailPreSignup(JObject input, ILambdaContext context)
    
        //Console.Write(input); //Print Input

        input["response"]["autoVerifyEmail"] = true;
        input["response"]["autoConfirmUser"] = true;

        return input;
    

【讨论】:

以上是关于在 DotNet 中创建 AWS Cognito PreSignup Lambda的主要内容,如果未能解决你的问题,请参考以下文章

AWS Amplify AppSync 使用在 Cognito 中创建的 Google 用户登录

如何在 Keycloak 中创建客户端以与 AWS Cognito 身份联合使用

AWS Cognito 内置登录重定向问题

AWS Cognito - SerializationException(在不期望的地方找到结构或映射的开始)

如何将 AWS Cognito 用户池用户存储在数据库(例如 DynamoDB)中?

API 无法识别向 AWS Boto3 Cognito-idp 传递参数