在DotNet中创建AWS Cognito PreSignup Lambda

Bit*_*der 5 c# amazon-web-services .net-core aws-lambda aws-cognito

使用.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 };
  }
}
Run Code Online (Sandbox Code Playgroud)

虽然请求成功并在使用以下示例请求调用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
}
Run Code Online (Sandbox Code Playgroud)

当通过.Net AmazonCognitoIdentityProviderClient执行实际的SignUp时,我收到一个错误:

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

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

有没有人有一个.Net Lambda函数的例子适用于AWS Cognito中的PreSignUp触发器?

Bit*_*der 11

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

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;
}
Run Code Online (Sandbox Code Playgroud)

这将捕获云计算日志中的有效负载,然后帮助您引导所需的强类型结构.

在我的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; }
}
Run Code Online (Sandbox Code Playgroud)

然后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;
    }
}
Run Code Online (Sandbox Code Playgroud)

希望这有助于其他任何人遇到为Cognito编写Lambda触发器的问题.


小智 7

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

因此,JObject参数不再合适,应替换为JsonElement。如果您尝试使用JObject这个新的序列化程序,您将收到错误,因为序列化程序不知道如何处理该对象。

您应该阅读本文以更好地了解其工作原理,但您可以访问 using 的JsonElement属性GetProperty("[insert property name here]")

例如:

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;
}
Run Code Online (Sandbox Code Playgroud)

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

  • 这是对的。JsonElement 类也可以很好地处理日志记录,因此按照 Bittercoder 建议的记录输入的起点,您仍然可以使用语法: `context.Logger.LogLine("Input was: " + input);` 来查看请求负载看起来像 Cloudwatch 日志中的内容。 (2认同)