Skip to main content
Version: 2.8.x(Latest)

Upon receiving the username and password at the login endpoint, it compares them with the information in the database. If correct, it generates and returns a Token, otherwise, it prompts "Username or password error."

Similarly, it follows the development principle of Three Boards: writing Api to generate Controller, writing core logic Logic, and having the Controller call Logic.

Add Api


api/users/v1/users.go

...

type LoginReq struct {
g.Meta `path:"users/login" method:"post" sm:"Login" tags:"User"`
Username string `json:"username" v:"required|length:3,12"`
Password string `json:"password" v:"required|length:6,16"`
}

type LoginRes struct {
Token string `json:"token" dc:"Add Authorization: token in the header for authentication-required interfaces"`
}

Don't forget to execute gf gen ctrl! You need to execute it every time you change the Api, not repeated in the text below.

Write Logic


The difficulty of the login logic lies in generating the Token. Prepare a random string JwtKey as the signature, and define it in the utility directory.

utility/jwt.go

package utility  

var JwtKey = []byte("db03d23b03ec405793b38f10592a2f34")

Write the core logic. First, perform a Where query based on the username. After data retrieval, encrypt the password again. If it matches the encrypted text in the database, it's a legitimate user and a Token is generated and returned.

internal/logic/users/account.go

package users  

import (
"context"
"errors"
"time"

"github.com/golang-jwt/jwt/v5"

"star/internal/dao"
"star/internal/model/entity"
"star/utility"
)

type userClaims struct {
Id uint
Username string
jwt.RegisteredClaims
}

func (u *Users) Login(ctx context.Context, username, password string) (tokenString string, err error) {
var user entity.Users
err = dao.Users.Ctx(ctx).Where("username", username).Scan(&user)
if err != nil {
return "", errors.New("Username or password error")
}

if user.Id == 0 {
return "", errors.New("User does not exist")
}

// Encrypt the password and compare it with the password in the database
if user.Password != encryptPassword(password) {
return "", errors.New("Username or password error")
}

// Generate token
uc := &userClaims{
Id: user.Id,
Username: user.Username,
RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(time.Now().Add(6 * time.Hour)),
},
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, uc)
return token.SignedString(utility.JwtKey)
}

As seen in the above code, we need to declare a struct UserClaims to store the signature information. It saves the Id and Username and sets the token validity to 6 hours. The final declared object needs to call the SignedString method and pass in JwtKey to generate a signature.

Controller calls Logic


internal/controller/users/users_v1_login.go

package users  

import (
"context"

"star/internal/logic/users"
"star/api/users/v1"
)

func (c *ControllerV1) Login(ctx context.Context, req *v1.LoginReq) (res *v1.LoginRes, err error) {
token, err := c.users.Login(ctx, req.Username, req.Password)
if err != nil {
return
}
return &v1.LoginRes{Token: token}, nil
}

Interface Testing


$ curl -X POST http://127.0.0.1:8000/v1/users/login -H "Content-Type: application/json" -d "{\"username\":\"oldme\", \"password\":\"123456\"}"

{
"code":0,
"message":"",
"data":{
"token":"eyJhbGciOi...ZY_ATzOU"
}
}