2025-10-21 10:30:53 +08:00

129 lines
3.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 admin
import (
"fmt"
"net/http"
"time"
"mini-chat/configs"
"mini-chat/internal/code"
"mini-chat/internal/pkg/core"
"mini-chat/internal/pkg/jwtoken"
"mini-chat/internal/pkg/utils"
"mini-chat/internal/pkg/validation"
"mini-chat/internal/proposal"
"gorm.io/gorm"
)
type loginRequest struct {
Username string `json:"username" binding:"required"` // 用户名
Password string `json:"password" binding:"required"` // 密码 (MD5加密后的密码)
}
type loginResponse struct {
Token string `json:"token"` // 登录成功后颁发的 Token
IsSuper int32 `json:"is_super"` // 是否是超级管理员(1:是 0:否)
}
// Login 管理员登录
// @Summary 管理员登录
// @Description 管理员登录
// @Tags 管理端.登录
// @Accept json
// @Produce json
// @Param RequestBody body loginRequest true "请求参数"
// @Success 200 {object} loginResponse
// @Failure 400 {object} code.Failure
// @Router /api/admin/login [post]
func (h *handler) Login() core.HandlerFunc {
return func(ctx core.Context) {
req := new(loginRequest)
res := new(loginResponse)
if err := ctx.ShouldBindJSON(req); err != nil {
ctx.AbortWithError(core.Error(
http.StatusBadRequest,
code.ParamBindError,
validation.Error(err)),
)
return
}
// 验证用户是否存在
info, err := h.readDB.Admin.WithContext(ctx.RequestContext()).Where(h.readDB.Admin.Username.Eq(req.Username)).First()
if err != nil && err != gorm.ErrRecordNotFound {
ctx.AbortWithError(core.Error(
http.StatusBadRequest,
code.AdminLoginError,
fmt.Sprintf("%s: %s", code.Text(code.AdminLoginError), err.Error())),
)
return
}
if err == gorm.ErrRecordNotFound {
ctx.AbortWithError(core.Error(
http.StatusBadRequest,
code.AdminLoginError,
fmt.Sprintf("%s: %s", code.Text(code.AdminLoginError), "账号不存在,请联系管理员。")),
)
return
}
// 验证登录状态
if info.LoginStatus != 1 {
ctx.AbortWithError(core.Error(
http.StatusBadRequest,
code.AdminLoginError,
fmt.Sprintf("%s账号已被禁用", code.Text(code.AdminLoginError))),
)
return
}
// 验证密码
if !utils.VerifyAdminHashedPassword(info.Password, req.Password) {
ctx.AbortWithError(core.Error(
http.StatusBadRequest,
code.AdminLoginError,
fmt.Sprintf("%s用户名或密码错误请联系管理员。", code.Text(code.AdminLoginError))),
)
return
}
// 设置 Session 信息
sessionUserInfo := proposal.SessionUserInfo{
Id: info.ID,
UserName: info.Username,
NickName: info.Nickname,
IsSuper: info.IsSuper,
Platform: "管理端",
}
// 设置载荷数据、有效期,生成 JWT Token String
tokenString, err := jwtoken.New(configs.Get().JWT.AdminSecret).Sign(sessionUserInfo, 3*24*time.Hour)
if err != nil {
ctx.AbortWithError(core.Error(
http.StatusBadRequest,
code.AdminLoginError,
fmt.Sprintf("%stoken 生成失败(%s)", code.Text(code.AdminLoginError), err.Error())),
)
return
}
info.LastLoginTime = time.Now()
info.LastLoginIP = utils.GetIP(ctx.Request())
info.LastLoginHash = utils.MD5(tokenString)
if err := h.writeDB.Admin.WithContext(ctx.RequestContext()).Save(info); err != nil {
ctx.AbortWithError(core.Error(
http.StatusBadRequest,
code.AdminLoginError,
fmt.Sprintf("%s%s", code.Text(code.AdminLoginError), err.Error())),
)
return
}
res.Token = tokenString
res.IsSuper = info.IsSuper
ctx.Payload(res)
}
}