Я использую AWS Cognito для аутентификации своих пользователей, и после аутентификации они могут вызывать мой API (API Gateway + Lambda). Все это я делаю с помощью Serverless Framework.
После аутентификации, когда они вызывают конечную точку, которая требует этой аутентификации, моя лямбда будет получать атрибуты пользователя через request.RequestContext.Authorizer["claims"]. У меня была идея создать промежуточное ПО для аутентификации, чтобы ввести текущего пользователя в контекст. Но я уверен, что что-то делаю не так (или можно поправить).
Как это работает:
my-lambda.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),
)
}
промежуточное ПО / 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)
}
}
модели / 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
}
У меня 2 вопроса:
ctx атрибутом user? Способ, которым пытаюсь, вижу ошибку ctx.user undefined (type context.Context has no field or method user).




1-й вопрос об использовании промежуточного программного обеспечения:
В таком подходе, конечно, нет ничего плохого. Возможно, функция будет выглядеть немного лучше, если вы определите тип функции и используете определенное имя. net/http делает то же самое с HandlerFunc:
type HandlerFunc func(ResponseWriter, *Request)
Что сделает подпись промежуточного программного обеспечения более разумной:
func AuthMiddleware(nextHop HandlerFunc) HandlerFunc
Обновлено: не определяет ли лямбда-библиотека такой тип для сигнатуры функции? Я ожидал, что один будет существовать.
Также я не знаю, имеет ли суффикс Middleware смысл в вашем случае, но я думаю, что какой-то суффикс должно иметь смысл, чтобы вы добавили немного большего контекста к имени функции и сделали его более понятным. AuthenticationMiddleware может быть примером.
Обновлено: только что увидел имя пакета. LGTM действительно.
2-й вопрос:
См. это для правильного использования context. Также существует распространенная ошибка: context.WithValue возвращает новый контекст для использования. Поэтому не следует ожидать изменения контекста переданного параметра и следует использовать возвращаемый новый.