在DotNet中创建AWS Cognito PreSignup Lambda

时间:2017-05-24 00:30:33

标签: 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 };
  }
}

虽然请求成功并在使用示例请求调用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执行实际的SignUp时,我收到错误:

  

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

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

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

3 个答案:

答案 0 :(得分:10)

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;
}

这可以捕获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触发器的问题。

答案 1 :(得分:2)

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

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

您应该阅读 this 以更好地了解它的工作原理,但您可以使用 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;
}

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

答案 2 :(得分:1)

这里已经有了另一个很好的答案。但是,我不是专业的.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;
    }
}