Files
ops2/backend/internal/handler/auth_handler.go
T
2026-03-31 20:06:53 +08:00

345 lines
8.2 KiB
Go

package handler
import (
"errors"
"strings"
"github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"
"gorm.io/gorm"
"ops/internal/service"
"ops/pkg/response"
)
// AuthHandler 用户认证处理器
type AuthHandler struct {
authService *service.AuthService
validate *validator.Validate
}
// LoginRequest 登录请求结构
type LoginRequest struct {
Name string `json:"name" binding:"required,min=3,max=50"`
Password string `json:"password" binding:"required,min=6,max=50"`
DeviceID string `json:"deviceID"`
IP string `json:"ip"`
Remember string `json:"remember"`
}
// LoginResponse 登录响应结构
type LoginResponse struct {
UserID uint `json:"userID"`
Name string `json:"name"`
AvatarURL string `json:"avatarURL"`
CookieValue string `json:"cookieValue"`
CookieExpireDate string `json:"cookieExpireDate"`
}
// RegisterRequest 注册请求结构
type RegisterRequest struct {
Name string `json:"name" binding:"required,min=3,max=50"`
Password string `json:"password" binding:"required,min=6,max=50"`
Email string `json:"email" binding:"omitempty,email"`
Phone string `json:"phone" binding:"omitempty,len=11"`
}
// RegisterResponse 注册响应结构
type RegisterResponse struct {
UserID uint `json:"userID"`
Name string `json:"name"`
CookieValue string `json:"cookieValue"`
}
// ForgotPasswordRequest 忘记密码请求
type ForgotPasswordRequest struct {
Name string `json:"name" binding:"required"`
Email string `json:"email" binding:"omitempty,email"`
Phone string `json:"phone" binding:"omitempty,len=11"`
}
// ResetPasswordRequest 重置密码请求
type ResetPasswordRequest struct {
Token string `json:"token" binding:"required"`
NewPassword string `json:"newPassword" binding:"required,min=6,max=50"`
}
// LogoutRequest 退出登录请求
type LogoutRequest struct {
CookieValue string `json:"cookieValue" binding:"required"`
DeviceID string `json:"deviceID"`
}
// NewAuthHandler 创建认证处理器
func NewAuthHandler(db *gorm.DB) *AuthHandler {
return &AuthHandler{
authService: service.NewAuthService(db),
validate: validator.New(),
}
}
// UserLogin 用户登录
func (h *AuthHandler) UserLogin(c *gin.Context) {
var req LoginRequest
// 绑定和验证请求
if err := c.ShouldBindJSON(&req); err != nil {
response.BadRequest(c, "Invalid request format")
return
}
// 验证请求参数
if err := h.validate.Struct(req); err != nil {
response.BadRequest(c, err.Error())
return
}
// 调用服务层
user, cookie, err := h.authService.Login(req.Name, req.Password, req.DeviceID, req.IP, req.Remember)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
response.Error(c, "-5", "User not found")
return
}
if strings.Contains(err.Error(), "password") {
response.Error(c, "-42", "Invalid password")
return
}
response.InternalError(c, err)
return
}
// 构建响应
resp := LoginResponse{
UserID: user.UserID,
Name: user.Name,
AvatarURL: user.AvatarURL,
CookieValue: cookie.Value,
CookieExpireDate: cookie.ExpireDate.Format("2006-01-02 15:04:05"),
}
response.Success(c, resp)
}
// UserRegister 用户注册
func (h *AuthHandler) UserRegister(c *gin.Context) {
var req RegisterRequest
// 绑定和验证请求
if err := c.ShouldBindJSON(&req); err != nil {
response.BadRequest(c, "Invalid request format")
return
}
// 验证请求参数
if err := h.validate.Struct(req); err != nil {
response.BadRequest(c, err.Error())
return
}
// 调用服务层
user, cookie, err := h.authService.Register(req.Name, req.Password, req.Email, req.Phone)
if err != nil {
if strings.Contains(err.Error(), "duplicate") || strings.Contains(err.Error(), "unique") {
response.Error(c, "-4", "Username already exists")
return
}
response.InternalError(c, err)
return
}
// 构建响应
resp := RegisterResponse{
UserID: user.UserID,
Name: user.Name,
CookieValue: cookie.Value,
}
response.Success(c, resp)
}
// UserForgotPassword 忘记密码
func (h *AuthHandler) UserForgotPassword(c *gin.Context) {
var req ForgotPasswordRequest
// 绑定和验证请求
if err := c.ShouldBindJSON(&req); err != nil {
response.BadRequest(c, "Invalid request format")
return
}
// 至少需要邮箱或手机号之一
if req.Email == "" && req.Phone == "" {
response.BadRequest(c, "Email or phone number is required")
return
}
// 验证请求参数
if err := h.validate.Struct(req); err != nil {
response.BadRequest(c, err.Error())
return
}
// 调用服务层
token, err := h.authService.ForgotPassword(req.Name, req.Email, req.Phone)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
response.Error(c, "-5", "User not found")
return
}
response.InternalError(c, err)
return
}
// 构建响应
response.Success(c, gin.H{
"resetToken": token,
"message": "Password reset instructions have been sent",
})
}
// UserResetPassword 重置密码
func (h *AuthHandler) UserResetPassword(c *gin.Context) {
var req ResetPasswordRequest
// 绑定和验证请求
if err := c.ShouldBindJSON(&req); err != nil {
response.BadRequest(c, "Invalid request format")
return
}
// 验证请求参数
if err := h.validate.Struct(req); err != nil {
response.BadRequest(c, err.Error())
return
}
// 调用服务层
err := h.authService.ResetPassword(req.Token, req.NewPassword)
if err != nil {
if strings.Contains(err.Error(), "invalid") || strings.Contains(err.Error(), "expired") {
response.Error(c, "-2", "Reset token is invalid or expired")
return
}
if errors.Is(err, gorm.ErrRecordNotFound) {
response.Error(c, "-5", "User not found")
return
}
response.InternalError(c, err)
return
}
response.Success(c, gin.H{
"message": "Password has been reset successfully",
})
}
// UserLogout 用户退出登录
func (h *AuthHandler) UserLogout(c *gin.Context) {
var req LogoutRequest
// 从认证中间件获取cookie值
cookieValue := getCookieFromContext(c)
if cookieValue == "" {
// 尝试从请求body获取
if err := c.ShouldBindJSON(&req); err != nil {
response.BadRequest(c, "Invalid request format")
return
}
cookieValue = req.CookieValue
}
if cookieValue == "" {
response.BadRequest(c, "Cookie value is required")
return
}
// 从请求中获取设备ID
deviceID := c.GetHeader("X-Device-ID")
if deviceID == "" && req.DeviceID != "" {
deviceID = req.DeviceID
}
// 调用服务层
err := h.authService.Logout(cookieValue, deviceID)
if err != nil {
response.InternalError(c, err)
return
}
response.Success(c, gin.H{
"message": "Logged out successfully",
})
}
// UserProfile 获取用户信息
func (h *AuthHandler) UserProfile(c *gin.Context) {
// 从认证中间件获取用户ID或名称
userID := getUserIDFromContext(c)
if userID == 0 {
response.Unauthorized(c)
return
}
// 调用服务层
user, err := h.authService.GetProfile(userID)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
response.Error(c, "-5", "User not found")
return
}
response.InternalError(c, err)
return
}
response.Success(c, user)
}
// UserUpdateProfile 更新用户信息
func (h *AuthHandler) UserUpdateProfile(c *gin.Context) {
// 从认证中间件获取用户ID
userID := getUserIDFromContext(c)
if userID == 0 {
response.Unauthorized(c)
return
}
// 解析更新请求
var updateData map[string]interface{}
if err := c.ShouldBindJSON(&updateData); err != nil {
response.BadRequest(c, "Invalid request format")
return
}
// 禁止更新某些字段
delete(updateData, "id")
delete(updateData, "name")
delete(updateData, "password")
delete(updateData, "createdAt")
// 调用服务层
user, err := h.authService.UpdateProfile(userID, updateData)
if err != nil {
response.InternalError(c, err)
return
}
response.Success(c, user)
}
// 辅助函数
func getCookieFromContext(c *gin.Context) string {
if cookie, exists := c.Get("userCookieValue"); exists && cookie != "" {
return cookie.(string)
}
return ""
}
func getUserIDFromContext(c *gin.Context) uint {
if userID, exists := c.Get("userID"); exists {
if id, ok := userID.(uint); ok {
return id
}
}
return 0
}