发布于 2026-01-05 1 阅读
0

验证 Golang 和 AWS Cognito

验证 Golang 和 AWS Cognito

O que é o cognito?

应用程序的验证部分是系统中最重要的部分,它具有多种感官、多种实施方式、安全性、验证性。

我们决定放弃Cognito的所有功能,并使用 AWS 来验证和验证网络应用程序和移动应用程序的有效性。

Cognito 平台是对设备响应和访问验证的平台,您可以通过 Cognito 访问地籍和设备信息,并使用 OAuth 来验证 OAuth 的有效性通常。

常用信息包括:电子邮件、姓名、电话、出生日期、昵称、性别、网站和其他个性化信息。

O cognito 不允许 trabalhar com“provedores federados”,可以登录社交媒体、Google、Facebook 和 GitHub,不可以发布帖子,也可以登录 cognito。

O que vamos vamos fazer

Vamos fazer alguns 端点最常用或认知功能,可使用、确认电子邮件、登录、使用公共汽车或使用令牌,以进行认知操作。

配置项目

Vamos fazer algo bem simples, não vamos nos preocupar com padrão de projeto, queremos abordar apenas or uso do cognito.

Para criar os 端点 vamos utilizar o gin

Vamos crariar os seguintes arquivos:

  • main.go项目应用程序的入口点

  • .env帕拉萨尔瓦作为认知的凭证

  • Uma Pasta chamada cognitoClient e dentro um arquivo chamadocognito.go

  • E um arquivo chamado request.http, para fazer as requisições

A estrutura vai ficar assim:

项目结构

在 AWS 上配置 cognito

启动代码、配置 AWS 认知、访问认知和总线、删除存储池、选择选项将用户目录添加到您的应用程序

提供商类型选择Cognito 用户池,可以选择允许使用电子邮件、用户名和电话登录,也可以选择电子邮件,选择更喜欢的选项,可以使用以下选项:

Cognito配置步骤1

É preciso configurar mais algumas coisas, vamos lá!

  • 密码策略模式允许使用Cognito默认值
  • 因素身份验证允许您登录并进行身份验证,可以使用此功能,可以通过无MFA 的方式实现该功能。
  • 此时,您可以通过电子邮件恢复用户帐户。

认知配置步骤2.1

认知配置步骤2.2

Próxima etapa:

  • 自助注册,您可以通过以下方式进行选择。
  • 认知辅助验证和确认允许认知者承担责任以确认我们的身份,并选择发送电子邮件、验证电子邮件地址的选项
  • 验证属性更改,然后通过电子邮件进行验证,以验证新的有效性。
  • 必需的属性,请选择要使用的新命令、您的选项、电子邮件 (já é obrigatório) 和姓名、一个 senha também já é obrigatório por padrão。
  • 自定义属性是可选的,可以作为个性化的附加说明,例如,您可以使用它来进行custom_id设置uuid

Ficou assim essa etapa:

认知配置步骤2.3

认知配置步骤2.4

认知配置步骤2.5

接下来,选择一个选项 使用Cognito 发送电子邮件,然后对不同的电子邮件进行预先配置。

Na próxima etapa, em User pool name coloque o nome que desejar em App client name , coloque também o nome que desejar e prosiga.

Na última etapa não vamos precisar alterar nada, basta Finalizar e criar o user pool.

您可以通过以下方式访问认知 > 用户池、选择用户池、使用应用程序列表、发送可用的撤销令牌、删除、验证外部功能。

Vamos precisar do id do pool, para poder utilizar o sdk do Go para a aws, para isso accesse o pool criado应用程序集成>应用程序客户端列表e vai ver o nosso客户端 ID

Cognito客户端ID

Vamos salvar esse id no nosso arquivo .env:

COGNITO_CLIENT_ID=client_id
Enter fullscreen mode Exit fullscreen mode

需要注意的是,作为 AWS 凭证、指示信息、进行配置/Users/seu-usuário/.aws时需要注意的事项,请执行以下操作。

Implementando o cognito

Vamos 将认知部分与 Arquivo 分开。

Cadastrando o usuário

Dentro do arquivo cognito.go,vamos inicializar nosso cognito e criar nossa 界面:

  package congnitoClient

  import (
    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/session"
    cognito "github.com/aws/aws-sdk-go/service/cognitoidentityprovider"
    "github.com/google/uuid"
  )

  type User struct {
    Name     string `json:"name" binding:"required"`
    Email    string `json:"email" binding:"required,email"`
    Password string `json:"password" binding:"required"`
  }

  type CognitoInterface interface {
    SignUp(user *User) error
  }

  type cognitoClient struct {
    cognitoClient *cognito.CognitoIdentityProvider
    appClientID   string
  }

  func NewCognitoClient(appClientId string) CognitoInterface {
    config := &aws.Config{Region: aws.String("us-east-1")}
    sess, err := session.NewSession(config)
    if err != nil {
      panic(err)
    }
    client := cognito.New(sess)

    return &cognitoClient{
      cognitoClient: client,
      appClientID:   appClientId,
    }
  }

  func (c *cognitoClient) SignUp(user *User) error {
    return nil
  }
Enter fullscreen mode Exit fullscreen mode

Primeiro criamos uma struct chamada User,essa struct vai ter os Campos do usuário que precisamos para salvar no cognito。

Depois criamos uma interfacechamada CognitoInterface、vamos ter os métodos que vamos usar、primiramente teremos apenas 或SignUpque vai receber um ponteiro da struct User

Depois outra struct chamada cognitoClientque vai conter nossa instância para o NewCognitoClientque vai ser nosso constructor。

如果您提到NewCognitoClient我们的构建器,您将无法访问该会话并返回该会话。 Essa conexão poderia se uma variável global, no nosso caso não vamos faz isso, vai de você verificar qual a melhor abordagem para o seu caso de uso.

Agora vamos implementar o SignUp:

  func (c *cognitoClient) SignUp(user *User) error {
    userCognito := &cognito.SignUpInput{
      ClientId: aws.String(c.appClientID),
      Username: aws.String(user.Email),
      Password: aws.String(user.Password),
      UserAttributes: []*cognito.AttributeType{
        {
          Name:  aws.String("name"),
          Value: aws.String(user.Name),
        },
        {
          Name:  aws.String("email"),
          Value: aws.String(user.Email),
        },
        {
          Name:  aws.String("custom:custom_id"),
          Value: aws.String(uuid.NewString()),
        },
      },
    }
    _, err := c.cognitoClient.SignUp(userCognito)
    if err != nil {
      return err
    }
    return nil
  }
Enter fullscreen mode Exit fullscreen mode

Vamos usar o AttributeTypedo cognito para montar os parâmetros vamos enfor para o SignUpdo sdk da aws, reare que o custom_idque é o nosso Campo individualizado, precisa que coloque o customantes, sem isso não vai ser aceito, apenas criamos um uuid com o pacote do google, esse Campo é apenas para大多数人都使用个性化属性。

O Campo ClientIdé Referente ao COGNITO_CLIENT_IDda nossa env, vamos repassar quando for iniciar o main.go.

Isso é o que precisamos para salvar o usuário, simples não é?

项目启动信息如下:

  go mod init <nome do seu projeto>
Enter fullscreen mode Exit fullscreen mode

安装所需的包:

  go mod tidy
Enter fullscreen mode Exit fullscreen mode

确认账户

Vamos criar outra função para verificar a conta do do do via e-mail, para verificar a conta o usuário vai precisar informar o codigo enaviado por e-mail, vamos criar uma nova s​​truct e adicionar or novo método ConfirmAccountna interface:

  type UserConfirmation struct {
    Email string `json:"email" binding:"required,email"`
    Code  string `json:"code" binding:"required"`
  }
Enter fullscreen mode Exit fullscreen mode
  type CognitoInterface interface {
    SignUp(user *User) error
    ConfirmAccount(user *UserConfirmation) error
  }
Enter fullscreen mode Exit fullscreen mode

Agora vamos implementar:

  func (c *cognitoClient) ConfirmAccount(user *UserConfirmation) error {
    confirmationInput := &cognito.ConfirmSignUpInput{
      Username:         aws.String(user.Email),
      ConfirmationCode: aws.String(user.Code),
      ClientId:         aws.String(c.appClientID),
    }
    _, err := c.cognitoClient.ConfirmSignUp(confirmationInput)
    if err != nil {
      return err
    }
    return nil
  }
Enter fullscreen mode Exit fullscreen mode

很简单,使用ConfirmSignUpInputpacote cognito para montar os parametros、lembrando que o Usernameé o e-mail do usuário。 Por último vamos chamar o ConfirmSignUppassando o confirmationInput.

Lembrando que apenas retornamos o erro, você poderia aprimorar and verificar os Tipos de mensagem de erro.

登录

Esse deve ser a funcionalidade que mais vai ser utilizada, vamos criar um método chamado SignIne uma struct:

  type UserLogin struct {
    Email    string `json:"email" binding:"required,email"`
    Password string `json:"password" binding:"required"`
  }
Enter fullscreen mode Exit fullscreen mode
  type CognitoInterface interface {
    SignUp(user *User) error
    ConfirmAccount(user *UserConfirmation) error
    SignIn(user *UserLogin) (string, error)
  }
Enter fullscreen mode Exit fullscreen mode

Nosso SignInvai receber um UserLogin.

Vamos implementar:

  func (c *cognitoClient) SignIn(user *UserLogin) (string, error) {
    authInput := &cognito.InitiateAuthInput{
      AuthFlow: aws.String("USER_PASSWORD_AUTH"),
      AuthParameters: aws.StringMap(map[string]string{
        "USERNAME": user.Email,
        "PASSWORD": user.Password,
      }),
      ClientId: aws.String(c.appClientID),
    }
    result, err := c.cognitoClient.InitiateAuth(authInput)
    if err != nil {
      return "", err
    }
    return *result.AuthenticationResult.AccessToken, nil
  }
Enter fullscreen mode Exit fullscreen mode

Vamos utilizar 功能InitiateAuth的 pacote cognito da aws,precisamos passar o username(电子邮件 do usuário),passwordeo AuthFlow,esse Campo se 裁判 a Tipo de acesso que vamos 许可,nosso caso o USER_PASSWORD_AUTH

Caso receba algum 错误:

You trusted all proxies, this is NOT safe. We recommend you to set a value

需要具备流程能力ALLOW_USER_PASSWORD_AUTH、配置访问权限和认知能力,例如:

用户池>选择 seu 池>应用程序集成>应用程序客户端列表>选择 um 客户端,可以使用以下方法:

认知流程 1

在编辑和身份验证流程中选择ALLOW_USER_PASSWORD_AUTH选项,即可轻松登录并使用电子邮件。

列出用户

Paramostrar como utilizar o token jwt fornecido pelo cognito vamos criar um end quemostra os bados do usuário salvos no cognito apenas com o token.

Vamos criar outra função chamada GetUserByTokenque vai receber um token and vai retornar uma struct do tipo GetUserOutputque vamos pegar do pacote do cognito.

  type CognitoInterface interface {
    SignUp(user *User) error
    ConfirmAccount(user *UserConfirmation) error
    SignIn(user *UserLogin) (string, error)
    GetUserByToken(token string) (*cognito.GetUserOutput, error)
  }
Enter fullscreen mode Exit fullscreen mode

请确认GetUserOutput结构体的结构

  type GetUserOutput struct {
    _ struct{} `type:"structure"`
    MFAOptions []*MFAOptionType `type:"list"`
    PreferredMfaSetting *string `type:"string"`
    UserAttributes []*AttributeType `type:"list" required:"true"`
    UserMFASettingList []*string `type:"list"`
    Username *string `min:"1" type:"string" required:"true" sensitive:"true"`
  }
Enter fullscreen mode Exit fullscreen mode

_ struct{}克里亚莫斯的个性化属性是我们的习惯,而不是我们的习惯custom_id

Vamos implementar:

  func (c *cognitoClient) GetUserByToken(token string) (*cognito.GetUserOutput, error) {
    input := &cognito.GetUserInput{
      AccessToken: aws.String(token),
    }
    result, err := c.cognitoClient.GetUser(input)
    if err != nil {
      return nil, err
    }
    return result, nil
  }
Enter fullscreen mode Exit fullscreen mode

利用GetUser认知能力,可以快速掌握认知能力AccessToken

Atualizando a senha

为了使您能够在新的电子邮件中准确地使用我们的服务,请在UserLogin新的环境中建立一个结构,以便重新提供服务,并为您提供新的功能。 Vamos 的功能如下UpdatePassword

  type CognitoInterface interface {
    SignUp(user *User) error
    ConfirmAccount(user *UserConfirmation) error
    SignIn(user *UserLogin) (string, error)
    GetUserByToken(token string) (*cognito.GetUserOutput, error)
    UpdatePassword(user *UserLogin) error
  }
Enter fullscreen mode Exit fullscreen mode

Vamos implementar:

  func (c *cognitoClient) UpdatePassword(user *UserLogin) error {
    input := &cognito.AdminSetUserPasswordInput{
      UserPoolId: aws.String(os.Getenv("COGNITO_USER_POOL_ID")),
      Username:   aws.String(user.Email),
      Password:   aws.String(user.Password),
      Permanent:  aws.Bool(true),
    }
    _, err := c.cognitoClient.AdminSetUserPassword(input)
    if err != nil {
      return err
    }
    return nil
  }
Enter fullscreen mode Exit fullscreen mode

Vamos usar a função AdminSetUserPassworddo pacote cognito, precisamos passar o e-mail do usuário ea nova s​​enha, além disso temos que passar o UserPoolId, vamos colocar no arquivo .envo COGNITO_USER_POOL_ID, parabuscar na aws basta acessar seu pool e copiar oUser pool ID

池 ID

Permanent如果您知道永久使用的信息,请注意您的使用情况,以及使用时的认知情况,false取决于您在应用程序中使用的策略。

Criando a main

Vamos criar nosso main.go,vai ser nesse arquivo que vamos iniciar o cognito e criar nossas rotas。

  func main() {
    err := godotenv.Load()
    if err != nil {
      panic(err)
    }
    cognitoClient := congnitoClient.NewCognitoClient(os.Getenv("COGNITO_CLIENT_ID"))
    r := gin.Default()

    fmt.Println("Server is running on port 8080")
    err = r.Run(":8080")
    if err != nil {
      panic(err)
    }
  }
Enter fullscreen mode Exit fullscreen mode

首先,我们要为客户提供服务,并为客户提供服务,为客户提供服务,为前门提供服务COGNITO_CLIENT_ID为杜松子酒和服务器提供服务,一切都足够了。

Criando os 端点

Criando um usuário

Vamos criar uma função dentro do próprio arquivo main.go, vamos chamar de CreateUser:

  func CreateUser(c *gin.Context, cognito congnitoClient.CognitoInterface) error {
    var user congnitoClient.User
    if err := c.ShouldBindJSON(&user); err != nil {
      return errors.New("invalid json")
    }
    err := cognito.SignUp(&user)
    if err != nil {
      return errors.New("could not create use")
    }
    return nil
  }
Enter fullscreen mode Exit fullscreen mode

Algo simples,apenas Convertemos 或 que recebemos no body para nossa struct usando 或ShouldBindJSONdo gin,depois chamamos 或SignUpque criamos no cognito.go

Agora vamos 的功能如下main.go

  r.POST("user", func(context *gin.Context) {
        err := CreateUser(context, cognitoClient)
        if err != nil {
            context.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
            return
        }
        context.JSON(http.StatusCreated, gin.H{"message": "user created"})
    })
Enter fullscreen mode Exit fullscreen mode

Chamamos a função que acabamos de criar CreateUser,se houver um erro lançamos um StatusBadRequest,caso tenha um sucesso um StatusCreated,vamos testar。

Vamos fazer um go mod tidybaixando todos os pacotes、depois vamos rodar 和 aplicação comgo run main.go

Agora podemos criar uma chamada no arquivo request.httpe executar:

POST http://localhost:8080/user HTTP/1.1
content-type: application/json

{
  "Name": "John Doe",
  "email": "wivobi1159@bitofee.com",
  "password": "SuperSenha@1234"
}
Enter fullscreen mode Exit fullscreen mode

Se tudo estiver correto vamos receber a mensagem:

{
  "message": "user created"
}
Enter fullscreen mode Exit fullscreen mode

Agora entrando no painel do cognito na aws, e acessando o pool depois os usuários, vamos ter nosso usuário lá dentro:

用户

确认用户

修复 criamos 标志,确认无误,vamos 确认!

Crie uma função chamada ConfirmAccountno arquivo main.go:

  func ConfirmAccount(c *gin.Context, cognito congnitoClient.CognitoInterface) error {
    var user congnitoClient.UserConfirmation
    if err := c.ShouldBindJSON(&user); err != nil {
      return errors.New("invalid json")
    }
    err := cognito.ConfirmAccount(&user)
    if err != nil {
      return errors.New("could not confirm user")
    }
    return nil
  }
Enter fullscreen mode Exit fullscreen mode

Mesmo conceito que já usamos, conversionamos o body para a struct UserConfirmatione repassamos ao ConfirmAccountdo cognito.go.

Vamos criar o endpoint:

  r.POST("user/confirmation", func(context *gin.Context) {
        err := ConfirmAccount(context, cognitoClient)
        if err != nil {
            context.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
            return
        }
        context.JSON(http.StatusCreated, gin.H{"message": "user confirmed"})
    })
Enter fullscreen mode Exit fullscreen mode

Também é simples, so tratamos o erro e retornamos uma mensagem, vamos criar nossa chamada e testar:

POST http://localhost:8080/user/confirmation HTTP/1.1
content-type: application/json

{
  "email": "wivobi1159@bitofee.com",
  "code": "363284"
}
Enter fullscreen mode Exit fullscreen mode

Vamos receber a mensagem:

{
  "message": "user confirmed"
}
Enter fullscreen mode Exit fullscreen mode

开始新的认知或认知,修复或确认,确认有效的电子邮件地址,使用临时电子邮件,最准确的信息,了解环境的认知和确认的信息以及准确的血清确认成功。

用户已确认

登录

Agora vamos criar nosso token,para isso no arquivo main.gocrie uma função chamada SignIn,essa função vai retornar um erro e um token。

  func SignIn(c *gin.Context, cognito congnitoClient.CognitoInterface) (string, error) {
    var user congnitoClient.UserLogin
    if err := c.ShouldBindJSON(&user); err != nil {
      return "", errors.New("invalid json")
    }
    token, err := cognito.SignIn(&user)
    if err != nil {
      return "", errors.New("could not sign in")
    }
    return token, nil
  }
Enter fullscreen mode Exit fullscreen mode

Mesmo padrão das demais funções、convertamos o body para a structUserLogin和 repassamos ao SignIndo cognito.go

Vamos criar o endpoint:

  r.POST("user/login", func(context *gin.Context) {
        token, err := SignIn(context, cognitoClient)
        if err != nil {
            context.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
            return
        }
        context.JSON(http.StatusCreated, gin.H{"token": token})
    })
Enter fullscreen mode Exit fullscreen mode

Agora retornamos um tokenao usuário, vamos criar a chamada e testa:

POST http://localhost:8080/user/login HTTP/1.1
content-type: application/json

{
  "email": "wivobi1159@bitofee.com",
  "password": "SuperSenha@1234"
}
Enter fullscreen mode Exit fullscreen mode

Ao fazer a chamada vamos receber nosso token jwt:

{
  "token": "token_here"
}
Enter fullscreen mode Exit fullscreen mode

用户 JWT 令牌

Se pegar o token jwt podemos ver o que tem dentro, usando o site jwt.io .

列出用户

Agora vamos listar os bados do usuário salvos no cognito apenas usando o token, para isso crie uma função chamada GetUserByTokenno main.goe vamos precisar de uma struct parapresentar o response que vamos devolver ao usuário, vamos criar no maintambém:

  type UserResponse struct {
    ID            string `json:"id"`
    Name          string `json:"name"`
    Email         string `json:"email"`
    CustomID      string `json:"custom_id"`
    EmailVerified bool   `json:"email_verified"`
  }

  func main() {}
Enter fullscreen mode Exit fullscreen mode

Agora a função:

  func GetUserByToken(c *gin.Context, cognito congnitoClient.CognitoInterface) (*UserResponse, error) {
    token := strings.TrimPrefix(c.GetHeader("Authorization"), "Bearer ")
    if token == "" {
      return nil, errors.New("token not found")
    }
    cognitoUser, err := cognito.GetUserByToken(token)
    if err != nil {
      return nil, errors.New("could not get user")
    }
    user := &UserResponse{}
    for _, attribute := range cognitoUser.UserAttributes {
      switch *attribute.Name {
      case "sub":
        user.ID = *attribute.Value
      case "name":
        user.Name = *attribute.Value
      case "email":
        user.Email = *attribute.Value
      case "custom:custom_id":
        user.CustomID = *attribute.Value
      case "email_verified":
        emailVerified, err := strconv.ParseBool(*attribute.Value)
        if err == nil {
          user.EmailVerified = emailVerified
        }
      }
    }
    return user, nil
  }
Enter fullscreen mode Exit fullscreen mode

这是一个主要功能,它是关于我们的结构的认知映射的概述UserResponse,它是一种for常见switch的方式,是一种新的方式,是一种典型的方式。包容性的个性化属性,精确的颜色或custom前值,como o custom:custom_id

如果验证失败或令牌没有标头,则不会通知您错误。

Vamos criar o endpoint:

  r.GET("user", func(context *gin.Context) {
        user, err := GetUserByToken(context, cognitoClient)
        if err != nil {
            if err.Error() == "token not found" {
                context.JSON(http.StatusUnauthorized, gin.H{"error": "token not found"})
                return
            }
            context.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
            return
        }
        context.JSON(http.StatusOK, gin.H{"user": user})
    })
Enter fullscreen mode Exit fullscreen mode

验证端点的信息、验证错误的提示以及token not found返回提示的情况StatusUnauthorized

Vamos testar:

GET http://localhost:8080/user HTTP/1.1
content-type: application/json
Authorization: Bearer token_jwt
Enter fullscreen mode Exit fullscreen mode

Vamos receber o usuário:

{
  "user": {
    "id": "50601dc9-7234-419a-8427-2a4bda92d33f",
    "name": "John Doe",
    "email": "wivobi1159@bitofee.com",
    "custom_id": "cb748d09-40de-457a-af23-ed9483d69f8d",
    "email_verified": true
  }
}
Enter fullscreen mode Exit fullscreen mode

Atualizando a senha

最后,请注意以下功能UpdatePassword

  func UpdatePassword(c *gin.Context, cognito congnitoClient.CognitoInterface) error {
    token := strings.TrimPrefix(c.GetHeader("Authorization"), "Bearer ")
    if token == "" {
      return errors.New("token not found")
    }
    var user congnitoClient.UserLogin
    if err := c.ShouldBindJSON(&user); err != nil {
      return errors.New("invalid json")
    }
    err := cognito.UpdatePassword(&user)
    if err != nil {
      return errors.New("could not update password")
    }
    return nil
  }
Enter fullscreen mode Exit fullscreen mode

但是,如果没有标头,则必须提供通知,否则无法恢复前面的功能。

Vamos criar o último 终点:

  r.PATCH("user/password", func(context *gin.Context) {
        err := UpdatePassword(context, cognitoClient)
        if err != nil {
            if err.Error() == "token not found" {
                context.JSON(http.StatusUnauthorized, gin.H{"error": "token not found"})
                return
            }
            context.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
            return
        }
        context.JSON(http.StatusOK, gin.H{"message": "password updated"})
    })
Enter fullscreen mode Exit fullscreen mode

Vamos fazer a chamada:

PATCH http://localhost:8080/user/password HTTP/1.1
content-type: application/json
Authorization: Bearer token_jwt

{
  "email": "wivobi1159@bitofee.com",
  "password": "NovaSenha2@2222"
}
Enter fullscreen mode Exit fullscreen mode

很快,我们就可以在 senha 上进行操作,并登录后发现错误,然后使用 nova s​​enha,即可使用该功能。

最终考虑因素

Nesse post abordamos um pouco sobre o cognito um dos muitos services da aws que muita gente não conhece mas que ajuda muito na evolução do seu sistema.

一个关于认知的实践,fazer um Login básico é simples, mas o cognito se destaca por já lhe entregar "pronto" um sistema de verificação de conta, opção Login com redes sociais (que pode ser bem chato de Implementar sem o coginito), autenticação de dois fatores entre entre, e ainda tem a segurança da aws para teger os bados do do usuário.

O cognito tem mais funcionalidade, vale a pena ver todas na documentação .

仓库链接

项目存储库

link do projeto no meu blog

Se inscreva e receba um aviso sobre novos posts, participar

文章来源:https://dev.to/wiliamvj/autenticacao-com-golang-e-aws-cognito-4ckh