>백엔드 개발 >Golang >Golang 및 AWS Cognito를 사용한 인증

Golang 및 AWS Cognito를 사용한 인증

WBOY
WBOY원래의
2024-08-19 06:32:11436검색

코그니토란 무엇인가요?

애플리케이션 인증은 시스템에서 매우 중요하지만 매우 민감하기 때문에 다양한 구현, 보안, 유효성 검사를 고려해야 합니다.

많은 사람들이 모르는 웹 및 모바일 애플리케이션에 대한 사용자 인증 및 검증에 도움을 줄 수 있는 AWS의 매우 유용한 도구인 Cognito에 대해 시연하는 게시물을 작성하기로 결정했습니다.

Cognito는 OAuth 토큰 생성 외에도 사용자 액세스 데이터 생성 및 검증은 물론 사용자 등록 및 정보 저장을 담당하는 AWS 플랫폼이며, Cognito는 모든 사용자 검증도 제공할 수 있습니다.

이메일, 이름, 전화번호, 생년월일, 별명, 성별, 웹사이트 등의 사용자 데이터를 생성할 수 있으며 사용자 정의 필드를 배치할 수도 있습니다.

Cognito를 사용하면 Google, Facebook, GitHub 등 소셜 로그인으로 알려진 "연합 공급자"와 작업할 수 있습니다. 이 게시물에서는 다루지 않지만 cognito를 사용하면 가능합니다.

우리는 무엇을 할 것인가?

cognito 작동 방식을 보여주기 위해 몇 가지 엔드포인트를 만들 예정이며, 사용자 생성, 이메일 확인, 로그인, cognito에서 제공하는 토큰을 사용하여 사용자 검색, 정보 업데이트 등을 할 것입니다.

프로젝트 설정

우리는 매우 간단한 일을 할 것입니다. 프로젝트 아버지에 대해 걱정하지 않고 지식의 활용만을 다루고 싶습니다.

엔드포인트를 생성하기 위해 gin을 사용할 것입니다.

다음 파일을 만들어 보겠습니다.

  • 프로젝트 루트에 있는 main.go 애플리케이션의 진입점

  • .env 인지 자격 증명 저장

  • cognitoClient라는 붙여넣기와 cognito.go라는 파일 내부

  • 요청을 완료하기 위한 request.http라는 파일이 있습니다.

구성은 다음과 같습니다.

Authentication with Golang and AWS Cognito

AWS에서 Cognito 설정

코드를 시작하기 전에 패널에 액세스하고 cognito로 검색하도록 AWS에서 cognito를 구성합니다. 풀을 생성한 후 앱에 사용자 디렉터리 추가 옵션을 선택합니다.

공급자 유형의 경우 Cognito 사용자 풀 옵션을 선택하고 이메일, 사용자 이름 및 전화를 사용한 로그인을 허용하도록 선택할 수 있습니다. 이메일만 선택할 수 있습니다. 선호하는 경우 첫 번째 단계로 이동을 선택하세요.

Authentication with Golang and AWS Cognito

더 구성해야 할 것이 있으니 어서 가세요!

  • 비밀번호 정책 모드를 사용하면 특정 정책을 선택할 수 있습니다. Cognito 기본값을 살펴보겠습니다.
  • 다단계 인증을 사용하면 로그인에 2단계 인증이 가능합니다. 필요에 따라 구현할 수도 있고 MFA 없음을 선택할 수도 있습니다.
  • 마지막으로 사용자 계정 복구, 계정 복구 방법을 선택할 수 있으며 이메일만 선택하면 됩니다.

Authentication with Golang and AWS Cognito

Authentication with Golang and AWS Cognito

다음 단계:

  • 셀프 서비스 가입, 누구나 가입할 수 있도록 허용하고 선택한 상태로 둡니다.
  • Cognito 지원 확인 및 확인, Cognito가 사용자 신원 확인을 담당하도록 허용하고 확인하고 이메일 메시지 보내기, 이메일 주소 확인 옵션도 선택합니다.
  • 속성 변경 확인, 이 옵션을 선택하면 사용자 이메일 업데이트를 다시 확인해야 합니다.
  • 필수 속성, 새 사용자를 생성하기 위해 필수로 만들 필드를 선택하고 옵션을 선택하면 이메일(및 이름)과 이름도 아버지에게 필수가 됩니다.
  • 사용자 정의 속성은 선택 사항이지만 사용자 정의 필드를 추가할 수 있습니다. 예를 들어 uuid가 될 custom_id라는 필드를 생성합니다.

이 단계도 발생했습니다.

Authentication with Golang and AWS Cognito

Authentication with Golang and AWS Cognito

Authentication with Golang and AWS Cognito

다음으로 Cognito로 이메일 보내기 옵션을 선택하면 이메일을 트리거하기 위해 아무것도 구성할 필요가 없습니다.

다음 단계에서 사용자 풀 이름앱 클라이언트 이름에 원하는 이름을 입력한 후 계속하세요.

마지막 단계에서는 아무것도 변경할 필요가 없으며 사용자 풀만 만들고 생성하면 됩니다.

모든 것, 액세스 또는 인식 > 사용자 풀, 방금 생성한 풀을 선택하면 이 부분에 애플리케이션의 모든 사용자가 나열되며 사용자의 토큰 취소, 비활성화, 기타 기능 확인이 가능합니다.

AWS용 Go SDK를 사용하고 생성된 풀에 액세스할 수 있도록 풀의 ID를 지정하겠습니다. 앱 통합 > 앱 클라이언트 목록 클라이언트 ID를 확인하세요.

Authentication with Golang and AWS Cognito

이 ID를 .env 파일에 저장해 보겠습니다.

COGNITO_CLIENT_ID=client_id

일반적으로 /Users/your-user/.aws 디렉터리에 있는 AWS 자격 증명이 여전히 필요하다는 점을 기억하고 아직 구성하지 않은 경우 여기에서 구성 방법을 참조하세요.

코그니토 구현

cognito 부분을 다른 파일로 분리해 보겠습니다.

사용자 등록

cognito.go 파일 내에서 cognito를 초기화하고 인터페이스를 생성합니다.

  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
  }

먼저 User라는 구조체를 만듭니다. 이 구조체에는 cognito에 저장해야 하는 사용자 필드가 있습니다.

그런 다음 CognitoInterface라는 인터페이스를 만들고 사용할 메서드를 갖게 됩니다. 먼저 User 구조체에 대한 포인터를 수신하는 SignUp만 갖게 됩니다.

그런 다음 생성자가 될 NewCognitoClient에 대한 인스턴스를 포함하는 cognitoClient라는 또 다른 구조체를 갖게 됩니다.

언급한 대로 NewCognitoClient는 생성자와 같으며 여기서 AWS로 세션을 생성하고 이 연결을 반환합니다. 이 연결은 전역 변수일 수 있습니다. 우리의 경우에는 이를 수행하지 않을 것이며 귀하의 사용 사례에 가장 적합한 접근 방식이 무엇인지 확인하는 것은 귀하에게 달려 있습니다.

이제 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
  }

Cognito의 AttributeType을 사용하여 AWS SDK의 SignUp으로 보낼 매개변수를 조합합니다. 사용자 정의 필드인 custom_id는 이전에 사용자 정의로 배치해야 하며 이것이 없으면 허용되지 않습니다. , 방금 Google 패키지로 uuid를 만들었습니다. 이 필드는 맞춤 속성을 사용하는 방법을 보여주기 위한 것입니다.

ClientId 필드는 환경의 COGNITO_CLIENT_ID를 참조하며 main.go를 시작할 때 이를 전달합니다.

이것이 바로 사용자를 살리기 위한 것인데 간단하지 않나요?

다음과 같이 프로젝트를 시작하는 것을 잊지 마세요.

  go mod init <your project name>

필요한 패키지를 설치하세요.

  go mod tidy

계정 확인

이메일을 통해 사용자 계정을 확인하는 또 다른 기능을 만들어 보겠습니다. 계정을 확인하려면 사용자는 이메일로 전송된 코드를 입력해야 합니다. 새 구조체를 생성하고 인터페이스에 새ConfirmAccount 메서드를 추가해 보겠습니다.

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

이제 구현해 보겠습니다.

  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
  }

매우 간단합니다. cognito 패키지의ConfirmSignUpInput을 사용하여 사용자 이름이 사용자의 이메일임을 기억하고 매개변수를 조합하겠습니다. 마지막으로confirmationInput을 전달하여ConfirmSignUp을 호출합니다.

오류만 반환했다는 점을 기억하고 오류 메시지 유형을 확인하고 개선하면 됩니다.

로그인

이것은 가장 많이 사용될 기능이어야 합니다. SignIn이라는 메서드와 구조체를 만들어 보겠습니다.

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

저희 로그인은 UserLogin을 수신하게 됩니다.

다음을 구현해 보겠습니다.

  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
  }

aws cognito 패키지의 InitiateAuth 기능을 사용할 것이며 사용자 이름(사용자 이메일), 비밀번호 및 AuthFlow를 전달해야 합니다. 이 필드는 허용할 액세스 유형을 나타냅니다(이 경우 USER_PASSWORD_AUTH).

다음과 같은 오류가 발생하는 경우:

모든 프록시를 신뢰하셨습니다. 이는 안전하지 않습니다. 값을 설정하는 것이 좋습니다

ALLOW_USER_PASSWORD_AUTH 흐름을 활성화하고 aws 패널에서 액세스 코그니토를 구성하려면 다음으로 이동해야 합니다.

사용자 풀 > 셀렉션스 풀 > 앱 통합 > 앱 클라이언트 목록 > 음 클라이언트를 선택하면 다음 화면이 열립니다:

Authentication with Golang and AWS Cognito

Click on edit and in Authentication flows select the option ALLOW_USER_PASSWORD_AUTH then save, with this you can now log in with the user's password and email.

Listando um usuário

Para mostrar como utilizar o token jwt fornecido pelo cognito vamos criar um endpoint que mostra os dados do usuário salvos no cognito apenas com o token.

Let's create another function called GetUserByToken that will receive a token and return a struct of type GetUserOutput that we will get from the cognito package.

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

If you click on GetUserOutput you will see what is inside this struct

  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"`
  }

inside the _ struct{} there are custom attributes that we created for our user, in our case the custom_id.

Let's implement:

  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
  }

We use GetUser from the cognito package, it only needs an AccessToken which is the token provided by cognito itself.

Updating password

Finally, we will update the user's password. To do this, we will need the email address and the new password. We already have the UserLogin struct with the fields we need. We will reuse it. If you wish, create a new one just for this function. Let's create the UpdatePassword function:

  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
  }

Let's implement:

  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
  }

We will use the AdminSetUserPassword function from the cognito package, we need to pass the user's email and the new password, in addition we have to pass the UserPoolId, we will put the COGNITO_USER_POOL_ID in the .env file, to search in aws just access your pool and copy the User pool ID

Authentication with Golang and AWS Cognito

We will also pass Permanent, informing that it is a permanent password, you could pass false, so Cognito would create a temporary password for the user, this will depend on the strategy you will use in your application.

Creating the main

Let's create our main.go, this will be the file where we will start cognito and create our routes.

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

First we will load our envs with the godotenv package, then we start our cognito client, passing the COGNITO_CLIENT_ID, which we got earlier, then we start gin and create a server, that's enough.

Creating the endpoints

Creating a user

Let's create a function inside the main.go file itself, let's call it 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
  }

Something simple, we just convert what we receive in the body to our struct using gin's ShouldBindJSON, then we call the SignUp that we created in cognito.go.

Now let's create the endpoint inside the main.go function:

  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"})
    })

We call the function we just created CreateUser, if there is an error we throw a StatusBadRequest, if it is successful a StatusCreated, let's test.

Let's do a go mod tidy downloading all the packages, then we'll run the application with go run main.go

Now we can create a call in the request.http file and execute:

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

{
  "Name": "John Doe",
  "email": "wivobi1159@bitofee.com",
  "password": "Pass@1234"
}

If everything is correct we will receive the message:

{
  "message": "user created"
}

Now entering the Cognito panel on AWS, and accessing the pool then the users, we will have our user there:

Authentication with Golang and AWS Cognito

Confirming a user

Note that the user we created above is not confirmed, let's confirm it!

Create a function called ConfirmAccount in the main.go file:

  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
  }

Same concept we used before, let's convert the body to the UserConfirmation struct and pass it to ConfirmAccount in cognito.go.

Let's create the 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"})
    })

It's also simple, we just handle the error and return a message, let's create our call and test it:

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

{
  "email": "wivobi1159@bitofee.com",
  "code": "363284"
}

We will receive the message:

{
  "message": "user confirmed"
}

Now accessing Cognito again on the AWS panel, notice that the user is confirmed, remembering that you need to enter a valid email, you can use a temporary email to play around, but it needs to be valid, as Cognito will send the confirmation code and it needs to be a valid code to confirm successfully.

Authentication with Golang and AWS Cognito

Login

Now let's create our token, to do this in the main.go file create a function called SignIn, this function will return an error and a 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
  }

Same pattern as the other functions, we convert the body to the UserLogin struct and pass it to SignIn of cognito.go.

Let's create the 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})
    })

Now we return a token to the user, let's create the call and test:

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

{
  "email": "wivobi1159@bitofee.com",
  "password": "Pass@1234"
}

When making the call we will receive our jwt token:

{
  "token": "token_here"
}

Authentication with Golang and AWS Cognito

If we get the jwt token we can see what's inside, using the website jwt.io.

Listing a user

Now we will list the user data saved in cognito using only the token, to do this create a function called GetUserByToken in main.go and we will need a struct to represent the response that we will return to the user, we will create it in main as well:

  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() {}

Now the function:

  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
  }

This will be the biggest function, we need to map what we receive from Cognito to our UserResponse struct, we do this with a for and a switch, of course we could improve it, but for the sake of example we will keep it like this. Also to map custom attributes we need to put custom before, like custom:custom_id.

We also check if the user passed the token in the header, if not we return an error.

Let's create the 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})
    })

We perform the same validation as the other endpoints, but now we check the error type and if it is of the token not found type we return a StatusUnauthorized.

Let's test:

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

Let's receive the user:

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

Updating password

Finally, let's create the UpdatePassword function that will update the user's password:

  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
  }

We also make it mandatory to inform the token in the header, the rest of the function is what we have already done previously.

Let's create the last endpoint:

  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"})
    })

Let's make the call:

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

{
  "email": "wivobi1159@bitofee.com",
  "password": "NovaSenha2@2222"
}

Now when you update your password and try to log in you will receive an error, and if you use the new password, everything will work.

Final considerations

In this post we talk a little about Cognito, one of the many AWS services that many people don't know about but that helps a lot in the evolution of your system.

Cognito's practicality goes beyond what I've discussed. Making a basic login is simple, but Cognito stands out for already providing you with an account verification system "ready", a login option with social networks (which can be quite annoying to implement without Coginito), two-factor authentication, among others, and it also has AWS security to protect user data.

Cognito has more functionality, it's worth seeing all of them in the documentation.

Repository link

Project repository

See the post on my blog here

Subscribe and receive notification of new posts, participate

위 내용은 Golang 및 AWS Cognito를 사용한 인증의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.