Version:0.0.1.dev.260202

feat: build core architecture & implement user auth modules 🚀
feat: 搭建核心架构并实现用户认证模块 🚀

Framework Migration: Switched from Hertz to Gin, providing a more idiomatic and lightweight web foundation. 
框架迁移:从 Hertz 切换至 Gin,构建了更符合 Go 惯例且轻量级的 Web 基础。

Architectural Overhaul: Refactored the 3-layer architecture from global-variable-based calls to Explicit Dependency Injection (DI) via New... factory functions. This significantly improves testability and decoupling. 🏗️
架构重构:将三层架构从基于“全局变量”的调用重构为通过 New... 工厂函数实现的显式依赖注入 (DI)。这大幅提升了代码的可测试性与解耦程度。🏗️

User Auth: Completed and tested Register, Login, and Token Refresh APIs with robust error handling and Bcrypt password hashing. 🔐
用户认证:完成了注册、登录与 Token 刷新接口并通过测试,包含健壮的错误处理与 Bcrypt 密码哈希加密。🔐

Config Management: Integrated Viper for centralized, environment-aware configuration management. ⚙️
配置管理:集成了 Viper,实现了中心化且具备环境感知能力的配置管理。⚙️

DevOps & Docs:
Added docker-compose.yml for seamless MySQL 8.0 & environment setup. 🐳
Updated README.md with corrections for mistakes in image quoting and formats. 📝
运维与文档:
新增 docker-compose.yml,实现 MySQL 8.0 环境的一键启动。🐳
更新 README.md,修改了一些图片引用和格式上小错误。📝
This commit is contained in:
LoveLosita
2026-02-02 21:32:21 +08:00
parent 8b45e0e332
commit 78aa38a6f3
19 changed files with 988 additions and 24 deletions

109
backend/service/user.go Normal file
View File

@@ -0,0 +1,109 @@
// Package service 业务逻辑层
// 包含所有核心业务逻辑
package service
import (
"errors"
"github.com/golang-jwt/jwt/v4"
"github.com/smartflow/backend/auth"
"github.com/smartflow/backend/dao"
"github.com/smartflow/backend/model"
"github.com/smartflow/backend/respond"
"github.com/smartflow/backend/utils"
"gorm.io/gorm"
)
type UserService struct {
// 伸出手:准备接住 DAO
repo *dao.UserDAO
}
// NewUserService组装 Service 的“工厂”
func NewUserService(repo *dao.UserDAO) *UserService {
return &UserService{
repo: repo, // 把传进来的 DAO 揣进口袋里
}
}
func (sv *UserService) UserRegister(user model.UserRegisterRequest) (*model.UserRegisterResponse, error) {
//检查是否有空字段
if user.Username == "" || user.Password == "" ||
user.PhoneNumber == "" {
return nil, respond.MissingParam
}
// 检查字段长度是否超过90%
if len(user.Username) > 45 || len(user.Password) > 229 || len(user.PhoneNumber) > 18 {
return nil, respond.ParamTooLong
}
//检查用户名是否已存在
result, err := sv.repo.IfUsernameExists(user.Username)
if err != nil {
return nil, err
}
if result {
return nil, respond.InvalidName
}
hashedPwd, err := utils.HashPassword(user.Password) //调用utils层的方法
if err != nil {
return nil, err
}
user.Password = hashedPwd //将user的密码字段改为加密后的密码
newUser, err := sv.repo.Create(user.Username, user.PhoneNumber, user.Password)
if err != nil {
return nil, err
}
//返回注册成功的用户ID
return &model.UserRegisterResponse{ID: newUser.ID}, nil
}
func (sv *UserService) UserLogin(req *model.UserLoginRequest) (*model.Tokens, error) {
var tokens model.Tokens
hashedPwd, err := sv.repo.GetUserHashedPasswordByName(req.Username) //调用dao层的方法
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, respond.WrongName
}
return nil, err
}
result, err := utils.CompareHashPwdAndPwd(hashedPwd, req.Password) //比较密码是否匹配
if err != nil { //其他错误
return &tokens, err
} else if !result { //密码不匹配
return nil, respond.WrongPwd
}
id, err := sv.repo.GetUserIDByName(req.Username)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, respond.WrongName
}
return nil, err
}
tokens.AccessToken, tokens.RefreshToken, err = auth.GenerateTokens(id) //生成jwt key
if err != nil { //其他错误
return nil, err
}
return &tokens, nil
}
func (sv *UserService) RefreshTokenHandler(refreshToken string) (*model.Tokens, error) {
// 验证刷新令牌
token, err := auth.ValidateRefreshToken(refreshToken)
if err != nil || !token.Valid { // 刷新令牌无效
return nil, respond.InvalidRefreshToken
}
// 生成新的访问令牌和刷新令牌
if claims, ok := token.Claims.(jwt.MapClaims); ok {
userID := int(claims["user_id"].(float64))
newAccessToken, newRefreshToken, err := auth.GenerateTokens(userID)
if err != nil {
return nil, err
}
// 返回新的访问令牌和刷新令牌
return &model.Tokens{AccessToken: newAccessToken, RefreshToken: newRefreshToken}, nil
} else {
return nil, respond.InvalidClaims
}
}