Files
st/server/service/app/auth.go

255 lines
6.4 KiB
Go

package app
import (
"errors"
"time"
"git.echol.cn/loser/st/server/global"
"git.echol.cn/loser/st/server/model/app"
"git.echol.cn/loser/st/server/model/app/request"
"git.echol.cn/loser/st/server/model/app/response"
"git.echol.cn/loser/st/server/utils"
"github.com/google/uuid"
"golang.org/x/crypto/bcrypt"
"gorm.io/gorm"
)
type AuthService struct{}
// Register 用户注册
func (s *AuthService) Register(req *request.RegisterRequest) error {
// 检查用户名是否已存在
var count int64
err := global.GVA_DB.Model(&app.AppUser{}).Where("username = ?", req.Username).Count(&count).Error
if err != nil {
return err
}
if count > 0 {
return errors.New("用户名已存在")
}
// 检查邮箱是否已存在
if req.Email != "" {
err = global.GVA_DB.Model(&app.AppUser{}).Where("email = ?", req.Email).Count(&count).Error
if err != nil {
return err
}
if count > 0 {
return errors.New("邮箱已被使用")
}
}
// 密码加密
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost)
if err != nil {
return errors.New("密码加密失败")
}
// 创建用户
user := app.AppUser{
UUID: uuid.New().String(),
Username: req.Username,
Password: string(hashedPassword),
NickName: req.NickName,
Email: req.Email,
Phone: req.Phone,
Status: "active",
Enable: true,
}
if user.NickName == "" {
user.NickName = req.Username
}
return global.GVA_DB.Create(&user).Error
}
// Login 用户登录
func (s *AuthService) Login(req *request.LoginRequest, ip string) (*response.LoginResponse, error) {
// 查询用户
var user app.AppUser
err := global.GVA_DB.Where("username = ?", req.Username).First(&user).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, errors.New("用户名或密码错误")
}
return nil, err
}
// 检查用户状态
if !user.Enable {
return nil, errors.New("账户已被禁用")
}
if user.Status != "active" {
return nil, errors.New("账户状态异常")
}
// 验证密码
err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(req.Password))
if err != nil {
return nil, errors.New("用户名或密码错误")
}
// 生成 Token
token, expiresAt, err := utils.CreateAppToken(user.ID, user.Username)
if err != nil {
return nil, errors.New("Token 生成失败")
}
// 生成刷新 Token
refreshToken, refreshExpiresAt, err := utils.CreateAppRefreshToken(user.ID, user.Username)
if err != nil {
return nil, errors.New("刷新 Token 生成失败")
}
// 更新最后登录信息
now := time.Now()
global.GVA_DB.Model(&user).Updates(map[string]interface{}{
"last_login_at": now,
"last_login_ip": ip,
})
// 保存会话信息(可选)
session := app.AppUserSession{
UserID: user.ID,
SessionToken: token,
RefreshToken: refreshToken,
ExpiresAt: time.Unix(expiresAt, 0),
RefreshExpiresAt: func() *time.Time { t := time.Unix(refreshExpiresAt, 0); return &t }(),
IPAddress: ip,
}
global.GVA_DB.Create(&session)
return &response.LoginResponse{
User: response.ToAppUserResponse(&user),
Token: token,
RefreshToken: refreshToken,
ExpiresAt: expiresAt,
}, nil
}
// RefreshToken 刷新 Token
func (s *AuthService) RefreshToken(req *request.RefreshTokenRequest) (*response.LoginResponse, error) {
// 解析刷新 Token
claims, err := utils.ParseAppToken(req.RefreshToken)
if err != nil {
return nil, errors.New("刷新 Token 无效")
}
// 查询用户
var user app.AppUser
err = global.GVA_DB.Where("id = ?", claims.UserID).First(&user).Error
if err != nil {
return nil, errors.New("用户不存在")
}
// 检查用户状态
if !user.Enable {
return nil, errors.New("账户已被禁用")
}
// 生成新的 Token
token, expiresAt, err := utils.CreateAppToken(user.ID, user.Username)
if err != nil {
return nil, errors.New("Token 生成失败")
}
// 生成新的刷新 Token
refreshToken, _, err := utils.CreateAppRefreshToken(user.ID, user.Username)
if err != nil {
return nil, errors.New("刷新 Token 生成失败")
}
return &response.LoginResponse{
User: response.ToAppUserResponse(&user),
Token: token,
RefreshToken: refreshToken,
ExpiresAt: expiresAt,
}, nil
}
// Logout 用户登出
func (s *AuthService) Logout(userID uint, token string) error {
// 删除会话记录
return global.GVA_DB.Where("user_id = ? AND session_token = ?", userID, token).
Delete(&app.AppUserSession{}).Error
}
// GetUserInfo 获取用户信息
func (s *AuthService) GetUserInfo(userID uint) (*response.AppUserResponse, error) {
var user app.AppUser
err := global.GVA_DB.Where("id = ?", userID).First(&user).Error
if err != nil {
return nil, err
}
resp := response.ToAppUserResponse(&user)
return &resp, nil
}
// UpdateProfile 更新用户信息
func (s *AuthService) UpdateProfile(userID uint, req *request.UpdateProfileRequest) error {
updates := make(map[string]interface{})
if req.NickName != "" {
updates["nick_name"] = req.NickName
}
if req.Email != "" {
// 检查邮箱是否已被其他用户使用
var count int64
err := global.GVA_DB.Model(&app.AppUser{}).
Where("email = ? AND id != ?", req.Email, userID).
Count(&count).Error
if err != nil {
return err
}
if count > 0 {
return errors.New("邮箱已被使用")
}
updates["email"] = req.Email
}
if req.Phone != "" {
updates["phone"] = req.Phone
}
if req.Avatar != "" {
updates["avatar"] = req.Avatar
}
if req.Preferences != "" {
updates["preferences"] = req.Preferences
}
if req.AISettings != "" {
updates["ai_settings"] = req.AISettings
}
if len(updates) == 0 {
return nil
}
return global.GVA_DB.Model(&app.AppUser{}).Where("id = ?", userID).Updates(updates).Error
}
// ChangePassword 修改密码
func (s *AuthService) ChangePassword(userID uint, req *request.ChangePasswordRequest) error {
// 查询用户
var user app.AppUser
err := global.GVA_DB.Where("id = ?", userID).First(&user).Error
if err != nil {
return err
}
// 验证旧密码
err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(req.OldPassword))
if err != nil {
return errors.New("原密码错误")
}
// 加密新密码
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(req.NewPassword), bcrypt.DefaultCost)
if err != nil {
return errors.New("密码加密失败")
}
// 更新密码
return global.GVA_DB.Model(&user).Update("password", string(hashedPassword)).Error
}