Files
NovaBlog/server/internal/handlers/auth.go

234 lines
6.1 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 handlers
import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/novablog/server/internal/database"
"github.com/novablog/server/internal/middleware"
"github.com/novablog/server/internal/models"
"github.com/novablog/server/internal/utils"
"gorm.io/gorm"
)
// AuthHandler 认证处理器
type AuthHandler struct {
jwtManager *utils.JWTManager
}
// NewAuthHandler 创建认证处理器
func NewAuthHandler(jwtManager *utils.JWTManager) *AuthHandler {
return &AuthHandler{
jwtManager: jwtManager,
}
}
// RegisterRequest 注册请求
type RegisterRequest struct {
Username string `json:"username" binding:"required,min=3,max=50"`
Email string `json:"email" binding:"required,email"`
Password string `json:"password" binding:"required,min=6,max=50"`
Nickname string `json:"nickname"`
}
// LoginRequest 登录请求
type LoginRequest struct {
Username string `json:"username" binding:"required"`
Password string `json:"password" binding:"required"`
}
// AuthResponse 认证响应
type AuthResponse struct {
Token string `json:"token"`
User models.User `json:"user"`
}
// Register 用户注册
func (h *AuthHandler) Register(c *gin.Context) {
var req RegisterRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// 检查用户名是否已存在
var existingUser models.User
if err := database.DB.Where("username = ?", req.Username).First(&existingUser).Error; err == nil {
c.JSON(http.StatusConflict, gin.H{"error": "username already exists"})
return
}
// 检查邮箱是否已存在
if err := database.DB.Where("email = ?", req.Email).First(&existingUser).Error; err == nil {
c.JSON(http.StatusConflict, gin.H{"error": "email already exists"})
return
}
// 哈希密码
hashedPassword, err := utils.HashPassword(req.Password)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to hash password"})
return
}
// 创建用户
user := models.User{
Username: req.Username,
Email: req.Email,
Password: hashedPassword,
Nickname: req.Nickname,
Role: "user",
}
if err := database.DB.Create(&user).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to create user"})
return
}
// 生成 Token
token, err := h.jwtManager.GenerateToken(user.ID, user.Username, user.Role)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to generate token"})
return
}
c.JSON(http.StatusCreated, AuthResponse{
Token: token,
User: user,
})
}
// Login 用户登录
func (h *AuthHandler) Login(c *gin.Context) {
var req LoginRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// 查找用户(支持用户名或邮箱登录)
var user models.User
if err := database.DB.Where("username = ? OR email = ?", req.Username, req.Username).First(&user).Error; err != nil {
if err == gorm.ErrRecordNotFound {
c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid credentials"})
return
}
c.JSON(http.StatusInternalServerError, gin.H{"error": "database error"})
return
}
// 验证密码
if !utils.CheckPassword(req.Password, user.Password) {
c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid credentials"})
return
}
// 生成 Token
token, err := h.jwtManager.GenerateToken(user.ID, user.Username, user.Role)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to generate token"})
return
}
c.JSON(http.StatusOK, AuthResponse{
Token: token,
User: user,
})
}
// GetCurrentUser 获取当前用户信息(通过 Authorization header
func (h *AuthHandler) GetCurrentUser(c *gin.Context) {
// 从 header 获取 token
authHeader := c.GetHeader("Authorization")
if authHeader == "" {
c.JSON(http.StatusUnauthorized, gin.H{"error": "no token provided"})
return
}
// 解析 Bearer token
tokenString := ""
if len(authHeader) > 7 && authHeader[:7] == "Bearer " {
tokenString = authHeader[7:]
} else {
c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid token format"})
return
}
// 验证 token
claims, err := h.jwtManager.ParseToken(tokenString)
if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid token"})
return
}
// 获取用户信息
var user models.User
if err := database.DB.First(&user, claims.UserID).Error; err != nil {
if err == gorm.ErrRecordNotFound {
c.JSON(http.StatusNotFound, gin.H{"error": "user not found"})
return
}
c.JSON(http.StatusInternalServerError, gin.H{"error": "database error"})
return
}
c.JSON(http.StatusOK, gin.H{"user": user})
}
// GetProfile 获取当前用户信息
func (h *AuthHandler) GetProfile(c *gin.Context) {
userID, _ := middleware.GetUserID(c)
var user models.User
if err := database.DB.First(&user, userID).Error; err != nil {
if err == gorm.ErrRecordNotFound {
c.JSON(http.StatusNotFound, gin.H{"error": "user not found"})
return
}
c.JSON(http.StatusInternalServerError, gin.H{"error": "database error"})
return
}
c.JSON(http.StatusOK, user)
}
// UpdateProfileRequest 更新用户信息请求
type UpdateProfileRequest struct {
Nickname string `json:"nickname"`
Avatar string `json:"avatar"`
Bio string `json:"bio"`
}
// UpdateProfile 更新用户信息
func (h *AuthHandler) UpdateProfile(c *gin.Context) {
userID, _ := middleware.GetUserID(c)
var req UpdateProfileRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// 更新用户信息
updates := map[string]interface{}{}
if req.Nickname != "" {
updates["nickname"] = req.Nickname
}
if req.Avatar != "" {
updates["avatar"] = req.Avatar
}
if req.Bio != "" {
updates["bio"] = req.Bio
}
if err := database.DB.Model(&models.User{}).Where("id = ?", userID).Updates(updates).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to update profile"})
return
}
// 返回更新后的用户信息
var user models.User
database.DB.First(&user, userID)
c.JSON(http.StatusOK, user)
}