Files
full/module/base/mgt/internal/logic/pub/login.go

160 lines
4.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package pub
import (
"crypto/md5"
"encoding/hex"
"errors"
"fmt"
"strconv"
"bsm/full/module/base/mgt/internal/impl"
"bsm/full/module/base/mgt/internal/models"
"bsm/full/module/base/mgt/internal/types"
"git.apinb.com/bsm-sdk/core/crypto/token"
"git.apinb.com/bsm-sdk/core/env"
"git.apinb.com/bsm-sdk/core/errcode"
"git.apinb.com/bsm-sdk/core/infra"
"git.apinb.com/bsm-sdk/core/printer"
"git.apinb.com/bsm-sdk/core/vars"
"github.com/gin-gonic/gin"
"golang.org/x/crypto/bcrypt"
"gorm.io/gorm"
)
// Login 登录
// @Summary 登录
// @Description 登录
// @Tags 登录
// @Accept application/json
// @Produce application/json
// @Param role body types.LoginRequest true "登录请求"
// @Security ApiKeyAuth
// @Success 200 {object} types.LoginResp "新增成功,返回token"
// @Router /login [post]
func Login(c *gin.Context) {
var (
request types.LoginRequest
resp = types.LoginResp{}
user = models.MgtUser{}
extend = map[string]string{}
err error
account string
pwd string
)
err = c.ShouldBindJSON(&request)
if err != nil {
infra.Response.Error(c, errcode.ErrJsonUnmarshal)
return
}
if request.Account != "" && request.Password != "" {
account = request.Account
pwd = request.Password
} else if request.AppId != "" && request.AppKey != "" {
account = request.AppId
pwd = request.AppKey
} else {
printer.Error("登录参数异常: 账号密码或AppId/AppKey必须提供")
infra.Response.Error(c, errcode.ErrInvalidArgument)
return
}
// 获取用户信息
if err = impl.DBService.Model(&models.MgtUser{}).Where("account=?", account).First(&user).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
infra.Response.Error(c, errcode.ErrRecordNotFound)
return
}
infra.Response.Error(c, errcode.ErrDB)
return
}
resp = types.LoginResp{Phone: user.Phone, Email: user.Email, Name: user.Name, UserId: user.ID, Account: user.Account, Avatar: user.Avatar, Identity: user.Identity}
// 检测Password与Status
if request.AppKey != "" {
err = checkAppKeyAndStatus(user.Password, pwd, int16(user.Status))
} else {
err = checkPwdAndStatus(user.Password, pwd, user.Salt, int16(user.Status))
}
if err != nil {
printer.Error("检测Password与Status异常: %v", err)
infra.Response.Error(c, err)
return
}
extend["id"] = strconv.Itoa(int(user.ID))
extend["Identity"] = user.Identity
extend["status"] = strconv.Itoa(int(user.Status))
extend["name"] = user.Name
// 获取token
resp.Token, err = token.New(env.Runtime.JwtSecretKey).GenerateJwt(uint(user.ID), user.Identity, c.ClientIP(), "", nil, extend)
if err != nil {
printer.Error("获取token异常: %v", err)
infra.Response.Error(c, err)
return
}
err = models.UpdateLastLoginDate(uint(user.ID))
if err != nil {
printer.Error("更新最后登录时间异常: %v", err)
infra.Response.Error(c, errcode.ErrInternal)
return
}
printer.Info("用户登录成功: account=%s, userId=%d", account, user.ID)
infra.Response.Success(c, resp)
}
func SaveToken(id int64, role, token string) error {
tokenKey := fmt.Sprintf("%d-%s-%s", uint(id), role, "token")
status := impl.RedisService.Client.Set(impl.RedisService.Ctx, tokenKey, token, 0)
if status.Val() != "OK" {
printer.Error("保存token失败: %v", errcode.ErrTokenAuthTokenChanged)
return errcode.ErrTokenAuthTokenChanged
}
return nil
}
func checkPwdAndStatus(userPwd, inPwd, salt string, stat int16) error {
// 账号是否禁用
if stat == vars.DisabledStatus {
printer.Error("检查账号状态异常: 账号已禁用")
return errcode.ErrUnavailable
}
err := bcrypt.CompareHashAndPassword([]byte(userPwd), []byte(inPwd+salt))
if err == nil {
return nil
}
// 如果bcrypt失败尝试MD5验证向后兼容旧用户
isBcrypt := len(userPwd) > 4 && (userPwd[0:4] == "$2a$" || userPwd[0:4] == "$2b$" || userPwd[0:4] == "$2y$")
if isBcrypt {
printer.Error("密码验证失败: bcrypt验证失败")
return errcode.ErrPassword
}
hash := md5.Sum([]byte(inPwd + salt))
md5Hash := hex.EncodeToString(hash[:])
if userPwd == md5Hash {
return nil
}
printer.Error("密码验证失败: 所有验证方式均失败")
return errcode.ErrPassword
}
func checkAppKeyAndStatus(userPwd, pwd string, stat int16) error {
if userPwd != pwd {
printer.Error("检查密码异常: 密码不匹配")
return errcode.ErrPassword
}
if stat == vars.DisabledStatus {
printer.Error("检查账号状态异常: 账号已禁用")
return errcode.ErrUnavailable
}
return nil
}