数据库基础实现
以mysql
作为例子,使用GORM
首先定义用户数据 ——
go
// /internal/db/model.go
type User struct {
ID uint `gorm:"primaryKey"`
Username string `gorm:"uniqueIndex;size:64;not null"`
Password string `gorm:"size:255;not null"` // 存储 bcrypt 哈希
CreatedAt time.Time
UpdatedAt time.Time
}
接着连接和初始化数据库 ——
go
// /internal/db/db.go
var DB *gorm.DB
func Init() error {
dsn := config.MySQLDSN()
gormDB, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
return err
}
// 自动迁移 User
err = gormDB.AutoMigrate(&User{})
if err != nil {
return err
}
DB = gormDB
return nil
}
然后CRUD
这类操作在handler
处实现,其中密码调用bcrypt
做一遍哈希加密
go
// /internal/db/auth.go
func HashPassword(password string) (string, error) {
bytes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
return string(bytes), err
}
func CheckPassword(hash, password string) bool {
err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
return err == nil
}
假设在已经初始化的数据库下,先提供注册、登录两个方法 ——
go
// internal/handler/auth.go
type registerReq struct {
Username string `json:"username" binding:"required,min=3"`
Password string `json:"password" binding:"required,min=6"`
}
func Register(c *gin.Context) {
var req registerReq
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
hashed, err := db.HashPassword(req.Password)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "密码加密失败"})
return
}
user := db.User{Username: req.Username, Password: hashed}
if err := db.DB.Create(&user).Error; err != nil {
c.JSON(http.StatusConflict, gin.H{"error": "用户名已存在"})
return
}
c.JSON(http.StatusCreated, gin.H{"message": "注册成功"})
}
go
// internal/handler/auth.go
var jwtKey = []byte(config.JWTSecret())
type loginReq struct {
Username string `json:"username" binding:"required"`
Password string `json:"password" binding:"required"`
}
func Login(c *gin.Context) {
var req loginReq
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
var user db.User
if err := db.DB.Where("username = ?", req.Username).First(&user).Error; err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "用户不存在"})
return
}
if !db.CheckPassword(user.Password, req.Password) {
c.JSON(http.StatusUnauthorized, gin.H{"error": "密码错误"})
return
}
// 生成 JWT
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"sub": user.ID,
"exp": time.Now().Add(24 * time.Hour).Unix(),
})
tokenString, err := token.SignedString(jwtKey)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Token生成失败"})
return
}
c.JSON(http.StatusOK, gin.H{"token": tokenString})
}
最后在主函数中初始化数据库和绑定路由
go
func main() {
config.LoadConfig("config/config.yaml")
err := db.Init()
if err != nil {
log.Fatalf("数据库连接失败: %v", err)
}
log.Println("✅ MySQL 已连接")
r := gin.Default()
r.POST("/register", handler.Register)
r.POST("/login", handler.Login)
}