129 lines
3.4 KiB
Go
129 lines
3.4 KiB
Go
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 /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("%s:token 生成失败(%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)
|
||
}
|
||
}
|