如何在AWS Lambda内正确创建身份验证中间件

I'm using AWS Cognito to authenticate my users, and once authenticated, they can call my API (API Gateway + Lambda). I'm doing all that using the Serverless Framework.

Once authenticated, when they call an endpoint that requires this authentication, my lambda will receive the user attributes through the request.RequestContext.Authorizer["claims"]. I had the idea of creating an authentication middleware to inject the current user into the context. But I'm certain that I'm doing something wrong (or can be improved).

How it works:

my-lambda-handler.go:

package main

import (
    "context"

    "github.com/aws/aws-lambda-go/events"
    "github.com/aws/aws-lambda-go/lambda"
    "github.com/company/api/middlewares"
)

func Handler(ctx context.Context, request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
    fmt.Println(ctx.user)

    return events.APIGatewayProxyResponse{}, nil
}

func main() {
    lambda.Start(
        middlewares.Authentication(Handler),
    )
}

middlewares/authentication.go

package middlewares

import (
    "context"

    "github.com/aws/aws-lambda-go/events"
    "github.com/company/api/models"
)

func Authentication(next func(context.Context, events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error)) func(context.Context, events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
    var user models.User

    return func(ctx context.Context, request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
        claims := request.RequestContext.Authorizer["claims"]

        // Find user by claims properties.
        if err := user.Current(claims); err != nil {
            return events.APIGatewayProxyResponse{}, err
        }

        ctx.user = user
        return next(ctx, request)
    }
}

models/user.go:

package models

import (
    "github.com/jinzhu/gorm"
    "github.com/mitchellh/mapstructure"
)

type User struct {
    gorm.Model
    // Override ID cause we are using cognito.
    Email string `gorm:"primary_key,not null"`
    Site  Site
}

func (u *User) Current(claims interface{}) error {
    if err := mapstructure.Decode(claims, u); err != nil {
        panic(err)
    }

    if err := Database.Find(u).Error; err != nil {
        return err
    }
    return nil
}

I have two questions:

  • Is this the right way to define a function (Authentication function) that receives a function and returns another function? Because it's too verbose, I'm feeling this is wrong.
  • Is there a way to augment the ctx with an user attribute? The way that I'm trying, I see the error ctx.user undefined (type context.Context has no field or method user)

Thanks in advance.