算了,后端我自己写吧
This commit is contained in:
@@ -0,0 +1,345 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user