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

登录接口收到用户名和密码后,与数据库中的信息做比对,如果正确则生成Token返回,否则提示”用户名或密码错误“。

同样遵循三板斧开发原则:编写Api生成Controller,编写核心逻辑LogicController调起Logic

添加Api


api/users/v1/users.go

...

type LoginReq struct {
g.Meta `path:"users/login" method:"post" sm:"登录" tags:"用户"`
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:"在需要鉴权的接口中header加入Authorization: token"`
}

别忘记执行gf gen ctrl哦!每次变更Api都需要执行它,后文不再重复提示。

编写Logic


登录逻辑的的难点在于生成Token。准备好一个随机字符串JwtKey用作签名,我们将其定义在utility目录下。

utility/jwt.go

package utility  

var JwtKey = []byte("db03d23b03ec405793b38f10592a2f34")

编写核心逻辑,先根据用户名进行Where查询,获取到数据后,将密码再次加密,如果和数据库中的密文一致则说明是合法用户,生成Token返回。

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 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("用户名或密码错误")
}

if user.Id == 0 {
return "", errors.New("用户不存在")
}

// 将密码加密后与数据库中的密码进行比对
if user.Password != encryptPassword(password) {
return "", errors.New("用户名或密码错误")
}

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

从上面的代码可以看到,我们需要声明一个结构体UserClaims保存签名信息,这里保存了IdUsername并设置了Token有效期为 6 个小时。最后的声明对象还需要调用SignedString方法传入JwtKey生成签名。

Controller调用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 := users.Login(ctx, req.Username, req.Password)
if err != nil {
return
}
return &v1.LoginRes{Token: token}, nil
}

接口测试


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