yanlongqi 52d50b97aa 集成PostgreSQL数据库并实现用户注册登录功能
主要改动:
- 集成 GORM 和 PostgreSQL 驱动
- 创建数据库配置模块 (pkg/config)
- 实现数据库连接和初始化 (internal/database)
- 更新用户模型支持 GORM 和 bcrypt 密码加密
- 重构用户注册和登录处理器使用数据库存储
- 删除旧的 users.json 文件存储方式
- 更新 README.md 和 CLAUDE.md 文档

技术栈:
- GORM v1.31.1 - ORM框架
- PostgreSQL - 数据库
- bcrypt - 密码加密

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-04 01:12:36 +08:00

163 lines
3.4 KiB
Go
Raw Permalink 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 (
"ankao/internal/database"
"ankao/internal/models"
"crypto/sha256"
"encoding/hex"
"fmt"
"net/http"
"time"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
// generateToken 生成简单的token实际项目应使用JWT
func generateToken(username string) string {
data := fmt.Sprintf("%s:%d", username, time.Now().Unix())
hash := sha256.Sum256([]byte(data))
return hex.EncodeToString(hash[:])
}
// Login 用户登录处理
func Login(c *gin.Context) {
var req models.LoginRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"success": false,
"message": "请求参数错误",
"error": err.Error(),
})
return
}
// 从数据库查找用户
var user models.User
db := database.GetDB()
result := db.Where("username = ?", req.Username).First(&user)
if result.Error != nil {
if result.Error == gorm.ErrRecordNotFound {
c.JSON(http.StatusUnauthorized, gin.H{
"success": false,
"message": "用户名或密码错误",
})
return
}
c.JSON(http.StatusInternalServerError, gin.H{
"success": false,
"message": "服务器错误",
"error": result.Error.Error(),
})
return
}
// 验证密码
if !user.CheckPassword(req.Password) {
c.JSON(http.StatusUnauthorized, gin.H{
"success": false,
"message": "用户名或密码错误",
})
return
}
// 生成token
token := generateToken(req.Username)
// 返回用户信息(不包含密码)
userInfo := models.UserInfoResponse{
Username: user.Username,
Avatar: user.Avatar,
Nickname: user.Nickname,
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "登录成功",
"data": models.LoginResponse{
Token: token,
User: userInfo,
},
})
}
// Register 用户注册处理
func Register(c *gin.Context) {
var req models.RegisterRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"success": false,
"message": "请求参数错误",
"error": err.Error(),
})
return
}
db := database.GetDB()
// 检查用户名是否已存在
var existingUser models.User
result := db.Where("username = ?", req.Username).First(&existingUser)
if result.Error == nil {
c.JSON(http.StatusBadRequest, gin.H{
"success": false,
"message": "用户名已存在",
})
return
}
// 创建新用户
newUser := models.User{
Username: req.Username,
Nickname: req.Nickname,
Avatar: "https://api.dicebear.com/7.x/avataaars/svg?seed=" + req.Username, // 使用用户名生成默认头像
}
// 如果没有提供昵称,使用用户名
if newUser.Nickname == "" {
newUser.Nickname = req.Username
}
// 加密密码
if err := newUser.HashPassword(req.Password); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"success": false,
"message": "密码加密失败",
"error": err.Error(),
})
return
}
// 保存到数据库
if err := db.Create(&newUser).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"success": false,
"message": "注册失败",
"error": err.Error(),
})
return
}
// 生成token
token := generateToken(req.Username)
// 返回用户信息
userInfo := models.UserInfoResponse{
Username: newUser.Username,
Avatar: newUser.Avatar,
Nickname: newUser.Nickname,
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "注册成功",
"data": models.LoginResponse{
Token: token,
User: userInfo,
},
})
}