」工欲善其事,必先利其器。「—孔子《論語.錄靈公》
首頁 > 程式設計 > 使用 Golang 和 AWS Cognito 進行身份驗證

使用 Golang 和 AWS Cognito 進行身份驗證

發佈於2024-08-27
瀏覽:496

What is cognito?

The authentication of an application is something very important in the system, but also very sensitive, there are various implementations, security, validation to be considered.

I decided to make a post demonstrating a about Cognito, a very nice tool from AWS that can help you in the authentication and validation of the user for Web and mobile applications that many people do not know.

Cognito is an AWS platform responsible for creating and validating user access data, as well as being able to register users and store their information, in addition to generating OAuth tokens, and Cognito can also provide all user validation.

We can create some user data such as: email, name, phone, birthdate, nickname, gender, website and many others, we can also place custom fields.

Cognito still allows us to work with "federated providers", known as social logins, such as Google, Facebook and GitHub, we are not going to address this post, but it is possible to do it with cognito.

What are we going to do?

We are going to make some endpoints to show how cognito works, we are going to create a user, confirm email, login, search for a user using the token provided by cognito, update information.

Setting up the project

We are going to do something very simple, we are not going to worry about the project father, we want to address only the use of knowledge.

To create the endpoints we are going to use gin.

Let's create the following files:

  • The entrypoint of our application main.go at the root of the project

  • .env To save cognitive credentials

  • A paste called cognitoClient and inside a file called cognito.go

  • There is a file called request.http, to complete your requests.

The structure will be as follows:

Authentication with Golang and AWS Cognito

Setting up Cognito on AWS

Before starting the code, we will configure the cognito in AWS, to access the panel and search by cognito, after we will create our pool, select the option Add user directories to your app.

For Provider types, select the Cognito user pool option, you can choose to allow login using email, user name and phone, you can only opt for email, select what you prefer, select assim to first stage:

Authentication with Golang and AWS Cognito

I need to configure some more things, let's go!

  • Password policy mode allows you to select a specific policy, let's deixar the Cognito defaults.
  • Multi-factor authentication allows our login to have two-factor authentication, let's go without, but you can implement it if desired, you can opt for No MFA.
  • Finally, or User account recovery, you can choose ways to recover your account, you can just choose email.

Authentication with Golang and AWS Cognito

Authentication with Golang and AWS Cognito

Next step:

  • Self-service sign-up, we will allow any person to do so, leave selected.
  • Cognito-assisted verification and confirmation, allow cognito to be responsible for confirming the user's identity, check it, and also select the option Send email message, verify email address.
  • Verifying attribute changes, check this option, so that updating the user's email needs to be validated again.
  • Required attributes, select the fields that you want to make mandatory to create a new user, you will select the options, email (and the name) and the name will also be required by your father.
  • Custom attributes, it is optional, but you can add custom fields, for example, you will create a field called custom_id which will be any uuid.

This stage also occurred:

Authentication with Golang and AWS Cognito

Authentication with Golang and AWS Cognito

Authentication with Golang and AWS Cognito

Next, select the Send email with Cognito option, so we do not need to configure anything to trigger the emails.

In the next step, in User pool name put the name you want in App client name, also put the name you want and continue.

In the last stage we will not need to alter anything, just finish and create the user pool.

With everything, access or cognito > User pools, select the pool that you just created, this part will list all the users of your application, and it is possible to revoke the user's token, deactivate, verify among other functionalities.

We are going to specify the id of the pool, to be able to use the Go sdk for aws, for access to the created pool App integration > App client list and see our Client ID:

Authentication with Golang and AWS Cognito

Let's save this id in our .env file:

COGNITO_CLIENT_ID=client_id

Remembering that you still need to have the AWS credentials, usually located in the /Users/your-user/.aws directory, if you haven't configured it yet, see here how to do it.

Implementing cognito

Let's separate the cognito part into another file.

Registering the user

Inside the cognito.go file, we will initialize our cognito and create our interface:

  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
  }

First we create a struct called User, this struct will have the user fields that we need to save in cognito.

Then we create an interface called CognitoInterface, we will have the methods that we will use, first we will only have SignUp which will receive a pointer to the User struct.

Then we will have another struct called cognitoClient that will contain our instance for NewCognitoClient that will be our constructor.

As mentioned, NewCognitoClient will be like our constructor, it is where we will create the session with AWS and return this connection. This connection could be a global variable, in our case we will not do this, it is up to you to check which is the best approach for your use case.

Now let's implement 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
  }

We will use the AttributeType from Cognito to assemble the parameters that we will send to the SignUp of the AWS SDK, note that the custom_id which is our custom field, needs to be placed custom before, without this it will not be accepted, we just created a uuid with the Google package, this field is just to show how to use custom attributes.

The ClientId field refers to the COGNITO_CLIENT_ID of our env, we will pass it on when starting main.go.

This is what we need to save the user, simple isn't it?

Don't forget to start the project with:

  go mod init 

And install the necessary packages:

  go mod tidy

Confirming the account

Let's create another function to verify the user's account via email. To verify the account, the user will need to enter the code sent by email. Let's create a new struct and add the new ConfirmAccount method to the interface:

  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
  }

Now let's implement:

  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
  }

It's very simple, we will use the ConfirmSignUpInput from the cognito package to assemble the parameters, remembering that the Username is the user's email. Finally, we will call ConfirmSignUp passing the confirmationInput.

Remembering that we only returned the error, you could improve and check the types of error messages.

Login

This should be the functionality that will be used the most, let's create a method called SignIn and a struct:

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

Our SignIn will receive a UserLogin.

Let's implement:

  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
  }

We will use the InitiateAuth function from the aws cognito package, we need to pass the username (user's email), password and the AuthFlow, this field refers to the type of access that we will allow, in our case USER_PASSWORD_AUTH.

If you receive an error like this:

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

It will be necessary to enable the ALLOW_USER_PASSWORD_AUTH flow, to configure it access cognito on the aws panel, go to:

User pools > Selecione seu pool > App integration > App client list > Selecione um client, will open this screen:

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": "[email protected]",
  "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": "[email protected]",
  "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": "[email protected]",
  "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": "[email protected]",
    "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": "[email protected]",
  "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

版本聲明 本文轉載於:https://dev.to/wiliamvj/authentication-with-golang-and-aws-cognito-577e?1如有侵犯,請聯絡[email protected]刪除
最新教學 更多>
  • 如何解決 MySQL C# 中的文字編碼問題?
    如何解決 MySQL C# 中的文字編碼問題?
    修復MySQL C# 中的文字編碼問題使用實體框架在C# 中處理MySQL 資料庫時,使用者可能會遇到文字編碼問題,特別是帶有特殊字符,例如“ë”,渲染不正確。本文探討了解決此常見問題的最合適的解決方案。 要修正編碼問題,必須執行以下操作:驗證排序規則設定: 確保所涉及的資料庫或表的排序規則與UTF...
    程式設計 發佈於2024-11-06
  • 如何將美麗搜尋與 Node.js 集成
    如何將美麗搜尋與 Node.js 集成
    作為 Node.js 開發人員,建立能夠提供快速且準確的搜尋結果的應用程式非常重要。使用者期望立即得到相關的回應,但實現起來可能具有挑戰性,特別是在處理大型資料集時。 這就是美麗搜尋的用武之地——一個為輕鬆滿足這些需求而構建的搜尋引擎。 什麼是美麗搜尋? Meilisearch ...
    程式設計 發佈於2024-11-06
  • 平行 JavaScript 機
    平行 JavaScript 機
    作者:Vladas Saulis,PE Prodata,克萊佩達,立陶宛 2024 年 5 月 18 日 抽象的 本文提出了一種新的程式設計模型,可以以簡單且自動平衡的方式利用多核心 CPU 系統。該模型還提出了一種更簡單的程式設計範例,用於在大多數大規模平行計算領域(例如天氣預報、核子物理、搜尋引...
    程式設計 發佈於2024-11-06
  • 推薦項目:人事管理系統資料庫設置
    推薦項目:人事管理系統資料庫設置
    LabEx 的這個綜合計畫提供了深入研究資料庫管理世界的寶貴機會,重點是人事管理系統的創建和實施。無論您是新手資料庫管理員還是經驗豐富的開發人員,這種實務經驗都將為您提供必要的技能,以便在關聯式資料庫環境中有效管理和操作資料。 深入了解資料庫基礎知識 這個專案首先引導您完成使用 s...
    程式設計 發佈於2024-11-06
  • Python 中實例方法和類別方法有什麼不同?
    Python 中實例方法和類別方法有什麼不同?
    類別與實例方法Python 的PEP 8 風格指南建議使用“self”作為實例方法的第一個參數,使用“ cls」作為類別方法的第一個參數。理解這兩類方法之間的區別對於有效的物件導向程式設計至關重要。 實例方法實例方法與類別的特定實例相關聯。它們對實例的資料進行操作,並且通常接收“self”作為它們的...
    程式設計 發佈於2024-11-06
  • 將 AdoptiumJDK 原始碼載入到 Eclipse IDE 中
    將 AdoptiumJDK 原始碼載入到 Eclipse IDE 中
    AdoptiumJDK 的安裝程式中沒有內建原始程式碼文件,如果您需要透過 Eclipse IDE 檢查如何使用任何本機 JDK 方法,這是不可能的。 依照以下步驟在Eclipse IDE中載入原始碼: 造訪 AdoptiumJDK 官方網站並按所需的 JDK 版本進行過濾,在我的例子中是 11....
    程式設計 發佈於2024-11-06
  • 絕對定位與相對定位:為什麼它們的行為如此不同?
    絕對定位與相對定位:為什麼它們的行為如此不同?
    了解絕對位置與相對位置:寬度、高度等處理網頁上的元素定位時,了解這些概念絕對位置與相對位置的區別至關重要。讓我們深入探討經常引起疑問的四個關鍵點:1。相對寬度與絕對寬度為何相對定位的div會自動佔據100%寬度,而絕對定位的div只佔據內容寬度? 原因是設定位置:absolute 從文件結構的正常流...
    程式設計 發佈於2024-11-06
  • Python、Node js 和 PHP 中用於驗證碼識別的頂層模組
    Python、Node js 和 PHP 中用於驗證碼識別的頂層模組
    在我们的自动化时代,大多数解决方案都可以免费找到,我现在不是在谈论解决数学问题,而是稍微复杂的任务,例如数据解析,和我们的例子一样,还有 recapcha 识别。但如何找到一个好的模块呢?毕竟,随着技术的发展,每个人都得到了它,无论是认真的开发人员还是彻头彻尾的骗子。 我分析了验证码识别模块的市场,...
    程式設計 發佈於2024-11-06
  • 以下是一些標題選項,重點關注問題格式和核心內容:

**選項 1(直接且簡潔):**

* **如何在 PHP 中有效率地循環多維數組?

**選項2
    以下是一些標題選項,重點關注問題格式和核心內容: **選項 1(直接且簡潔):** * **如何在 PHP 中有效率地循環多維數組? **選項2
    在 PHP 中循環多維數組多維數組可能是解析的一個挑戰,特別是在處理不同深度級別和非順序索引時。考慮一個保存事件資訊的數組,其中可以包含多個藝術家及其相應的鏈接,如下所示:array(2) { [1]=> array(3) { ["eventID"]...
    程式設計 發佈於2024-11-06
  • 透過 Linting 提高程式碼品質
    透過 Linting 提高程式碼品質
    Whenever I start a new project, one of the first things I do is put in place a code linter. For the uninitiated, linters analyze your project and call...
    程式設計 發佈於2024-11-06
  • 如何有效執行JavaScript中的回呼函數?
    如何有效執行JavaScript中的回呼函數?
    理解JavaScript 中回呼函數的本質在JavaScript 中,回呼函數提供了一種方便的機制,可以在另一個函數完成後執行一個函數它的執行。雖然概念很簡單,但回調的最佳實作有時可能不清楚。讓我們探討一個簡化的範例:var myCallBackExample = { myFirstFunc...
    程式設計 發佈於2024-11-06
  • Vue 框架簡介
    Vue 框架簡介
    What is Vue? from the Vue website Vue is a "progressive" JavaScript framework for building user interfaces. It works by build...
    程式設計 發佈於2024-11-06
  • 逃離戲劇:為什麼 HydePHP 是您的 WordPress 替代品
    逃離戲劇:為什麼 HydePHP 是您的 WordPress 替代品
    WordPress 戲劇 隨著 WordPress 生態系統面臨前所未有的混亂,許多開發人員和網站所有者正在重新考慮他們的平台選擇。最近 WordPress 共同創辦人 Matt Mullenweg 和 WP Engine 之間的衝突凸顯了 WordPress 社群內的控制、貢獻和...
    程式設計 發佈於2024-11-06
  • Go 中的並發模式;工作池和扇出/扇入
    Go 中的並發模式;工作池和扇出/扇入
    Go 以其卓越的並發模型而聞名,但許多開發人員只專注於 goroutine 和通道。然而,工作池和扇出/扇入等並發模式提供了真正的效率。 本文將介紹這些進階概念,幫助您最大限度地提高 Go 應用程式的吞吐量。 為什麼並發很重要 並發允許程式有效率地執行任務,特別是在處理 I/O ...
    程式設計 發佈於2024-11-06
  • 如何在 C++ 中將單一字元轉換為 std::string?
    如何在 C++ 中將單一字元轉換為 std::string?
    從單字建立字串從單一字元建立字串人們可能會遇到需要將表示為char 資料類型的單字轉換為std:: string。從字串中取得字元很簡單,只需在所需位置索引字串即可。然而,相反的過程需要不同的方法。 要從單字建立std::string,可以使用多種方法:char c = 34; std::strin...
    程式設計 發佈於2024-11-06

免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。

Copyright© 2022 湘ICP备2022001581号-3