登录功能的实现
v1.POST("/login", controller.LoginHandler)
controller
func LoginHandler(c *gin.Context) {
// 1.获取请求参数及参数校验
p := new(models.ParamLogin)
if err := c.ShouldBindJSON(p); err != nil {
// 请求参数有误,直接返回响应
zap.L().Error("Login with invalid param", zap.Error(err))
// 判断err是不是validator.ValidationErrors 类型
errs, ok := err.(validator.ValidationErrors)
if !ok {
ResponseError(c, CodeInvalidParam)
return
}
ResponseErrorWithMsg(c, CodeInvalidParam, removeTopStruct(errs.Translate(trans)))
return
}
// 2.业务逻辑处理
user, err := logic.Login(p)
if err != nil {
zap.L().Error("logic.Login failed", zap.String("username", p.Username), zap.Error(err))
if errors.Is(err, mysql.ErrorUserNotExist) {
ResponseError(c, CodeUserNotExist)
return
}
ResponseError(c, CodeInvalidPassword)
return
}
// 3.返回响应
ResponseSuccess(c, gin.H{
"user_id": fmt.Sprintf("%d", user.UserID), // id值大于1<<53-1 int64类型的最大值是1<<63-1
"user_name": user.Username,
"token": user.Token,
})
}
logic
func Login(p *models.ParamLogin) (user *models.User, err error) {
user = &models.User{
Username: p.Username,
Password: p.Password,
}
// 传递的是指针,就能拿到user.UserID
if err := mysql.Login(user); err != nil {
return nil, err
}
// 生成JWT
token, err := jwt.GenToken(user.UserID, user.Username)
if err != nil {
return
}
user.Token = token
return
}
mysql
func Login(user *models.User) (err error) {
oPassword := user.Password // 用户登录的密码
sqlStr := `select user_id, username, password from user where username=?`
err = db.Get(user, sqlStr, user.Username)
if err == sql.ErrNoRows {
return ErrorUserNotExist
}
if err != nil {
// 查询数据库失败
return err
}
// 判断密码是否正确
password := encryptPassword(oPassword)
if password != user.Password {
return ErrorInvalidPassword
}
return
}
// GetUserById 根据id获取用户信息
func GetUserById(uid int64) (user *models.User, err error) {
user = new(models.User)
sqlStr := `select user_id, username from user where user_id = ?`
err = db.Get(user, sqlStr, uid)
return
}
model
// ParamLogin 登录请求参数
type ParamLogin struct {
Username string `json:"username" binding:"required"`
Password string `json:"password" binding:"required"`
}
JTW实现用户的认证
// JWTAuthMiddleware 基于JWT的认证中间件
func JWTAuthMiddleware() func(c *gin.Context) {
return func(c *gin.Context) {
// 客户端携带Token有三种方式 1.放在请求头 2.放在请求体 3.放在URI
// 这里假设Token放在Header的Authorization中,并使用Bearer开头
// Authorization: Bearer xxxxxxx.xxx.xxx / X-TOKEN: xxx.xxx.xx
// 这里的具体实现方式要依据你的实际业务情况决定
authHeader := c.Request.Header.Get("Authorization")
if authHeader == "" {
controller.ResponseError(c, controller.CodeNeedLogin)
c.Abort()
return
}
// 按空格分割
parts := strings.SplitN(authHeader, " ", 2)
if !(len(parts) == 2 && parts[0] == "Bearer") {
controller.ResponseError(c, controller.CodeInvalidToken)
c.Abort()
return
}
// parts[1]是获取到的tokenString,我们使用之前定义好的解析JWT的函数来解析它
mc, err := jwt.ParseToken(parts[1])
if err != nil {
controller.ResponseError(c, controller.CodeInvalidToken)
c.Abort()
return
}
// 将当前请求的userID信息保存到请求的上下文c上
c.Set(controller.CtxUserIDKey, mc.UserID)
c.Next() // 后续的处理请求的函数中 可以用过c.Get(CtxUserIDKey) 来获取当前请求的用户信息
}
}