Files
go_typecho/handlers/auth.go
T
2026-08-06 14:48:42 +08:00

196 lines
4.8 KiB
Go

package handlers
import (
"log/slog"
"net/http"
"time"
"goblog/database"
"goblog/models"
"github.com/gin-gonic/gin"
"github.com/golang-jwt/jwt/v5"
)
var jwtSecret = []byte("your-secret-key-change-in-production")
func JWTSecret() []byte {
return jwtSecret
}
// 登录请求
type LoginRequest struct {
Username string `json:"username" binding:"required"`
Password string `json:"password" binding:"required"`
}
// 注册请求
type RegisterRequest struct {
Username string `json:"username" binding:"required,min=3,max=50"`
Password string `json:"password" binding:"required,min=6"`
Nickname string `json:"nickname"`
Email string `json:"email" binding:"required,email"`
}
// JWT Claims
type Claims struct {
UserID uint `json:"user_id"`
Username string `json:"username"`
Role string `json:"role"`
jwt.RegisteredClaims
}
// 登录
func 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 = ?", req.Username).First(&user).Error; err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "用户名或密码错误"})
return
}
if user.Status == 0 || !user.IsActive {
c.JSON(http.StatusForbidden, gin.H{"error": "账号已被禁用"})
return
}
// 使用 User 模型的 CheckPassword 方法
if !user.CheckPassword(req.Password) {
c.JSON(http.StatusUnauthorized, gin.H{"error": "用户名或密码错误"})
return
}
// 记录登录信息
if err := user.RecordLogin(database.DB); err != nil {
slog.Warn("记录登录信息失败", "user_id", user.ID, "error", err)
}
// 生成 JWT
claims := Claims{
UserID: user.ID,
Username: user.Username,
Role: user.Role,
RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(time.Now().Add(7 * 24 * time.Hour)),
IssuedAt: jwt.NewNumericDate(time.Now()),
},
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
tokenString, err := token.SignedString(jwtSecret)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "生成令牌失败"})
return
}
c.JSON(http.StatusOK, gin.H{
"token": tokenString,
"user": gin.H{
"id": user.ID,
"username": user.Username,
"nickname": user.Nickname,
"email": user.Email,
"role": user.Role,
"avatar": user.Avatar,
"last_login_at": user.LastLoginAt,
"login_count": user.LoginCount,
},
})
}
// 获取当前用户信息
func GetCurrentUser(c *gin.Context) {
userID, _ := c.Get("userID")
var user models.User
if err := database.DB.First(&user, userID).Error; err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "用户不存在"})
return
}
c.JSON(http.StatusOK, gin.H{"data": user})
}
// 更新用户信息
func UpdateUser(c *gin.Context) {
userID, _ := c.Get("userID")
var user models.User
if err := database.DB.First(&user, userID).Error; err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "用户不存在"})
return
}
var req struct {
Nickname string `json:"nickname"`
Email string `json:"email"`
Avatar string `json:"avatar"`
}
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.Email != "" {
updates["email"] = req.Email
}
if req.Avatar != "" {
updates["avatar"] = req.Avatar
}
if err := database.DB.Model(&user).Updates(updates).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "更新失败"})
return
}
c.JSON(http.StatusOK, gin.H{"data": user})
}
// 修改密码
func ChangePassword(c *gin.Context) {
userID, _ := c.Get("userID")
var user models.User
if err := database.DB.First(&user, userID).Error; err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "用户不存在"})
return
}
var req struct {
OldPassword string `json:"old_password" binding:"required"`
NewPassword string `json:"new_password" binding:"required,min=6"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// 使用 User 模型的 CheckPassword 方法
if !user.CheckPassword(req.OldPassword) {
c.JSON(http.StatusBadRequest, gin.H{"error": "原密码错误"})
return
}
// 使用 User 模型的 SetPassword 方法
if err := user.SetPassword(req.NewPassword); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "密码加密失败"})
return
}
if err := database.DB.Save(&user).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "修改密码失败"})
return
}
c.JSON(http.StatusOK, gin.H{"message": "密码修改成功"})
}