Files
Meshray-Manager/internal/service/user.go
T
zkcoi e9ca2f7d70 fix: rename manager module to git.zkcoi.com/zkcoi/Meshray-Manager
- go.mod module path matches repo zkcoi/Meshray-Manager (case-distinct from zkcoi/Meshray/core)
- rewrite internal imports meshray/{internal,web,pkg} -> Meshray-Manager/... (core refs kept)
- sync README.md / install.sh repo URLs; add CHANGELOG entry
2026-07-15 16:25:46 +08:00

222 lines
6.1 KiB
Go

package service
import (
"crypto/rand"
"encoding/base64"
"errors"
"git.zkcoi.com/zkcoi/Meshray-Manager/internal/model"
"git.zkcoi.com/zkcoi/Meshray-Manager/internal/store/sqlite"
"golang.org/x/crypto/bcrypt"
"gorm.io/gorm"
)
// 字符集用于生成随机密码(保留用于特殊场景)
const passwordChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*"
// generateRandomPassword 使用 crypto/rand 生成安全的随机密码
func generateRandomPassword(length int) string {
b := make([]byte, length)
_, err := rand.Read(b)
if err != nil {
// 极端情况下回退到简单方案(几乎不会发生)
return "REPLACE_WITH_SECURE_PASSWORD"
}
// 使用 Base64 编码,确保包含各种字符
encoded := base64.StdEncoding.EncodeToString(b)
// 截取所需长度(Base64 编码后长度为 4/3 倍)
if len(encoded) >= length {
return encoded[:length]
}
return encoded
}
// GenerateRandomPassword 生成随机密码(公开函数)
func GenerateRandomPassword(length int) string {
return generateRandomPassword(length)
}
// UserService 用户服务
type UserService struct {
store *sqlite.Store
}
// NewUserService 创建用户服务实例
func NewUserService(store *sqlite.Store) *UserService {
return &UserService{store: store}
}
// InitializeAdmin 初始化管理员账户(首次启动时调用)
func (s *UserService) InitializeAdmin() (username, password string, err error) {
// 检查是否已存在 admin 用户
var existingUser model.User
if err := s.store.DB().Where("role = ?", "admin").First(&existingUser).Error; err == nil {
// 已存在,返回当前用户名(密码不返回)
return existingUser.Username, "", nil
}
// 生成随机密码
randomPassword := generateRandomPassword(16)
// 密码加密
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(randomPassword), bcrypt.DefaultCost)
if err != nil {
return "", "", err
}
// 创建 admin 用户
adminUser := &model.User{
Username: "admin",
PasswordHash: string(hashedPassword),
Email: "",
Role: "admin",
Status: "active",
}
if err := s.store.DB().Create(adminUser).Error; err != nil {
return "", "", err
}
return "admin", randomPassword, nil
}
// Authenticate 验证用户登录
func (s *UserService) Authenticate(username, password string) (*model.User, error) {
var user model.User
if err := s.store.DB().Where("username = ?", username).First(&user).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, errors.New("用户不存在")
}
return nil, err
}
// 验证密码
if err := bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(password)); err != nil {
return nil, errors.New("密码错误")
}
// 检查用户状态
if user.Status != "active" {
return nil, errors.New("账户已被禁用")
}
return &user, nil
}
// ChangePasswordRequest 修改密码请求
type ChangePasswordRequest struct {
OldPassword string `json:"old_password"`
NewPassword string `json:"new_password"`
}
// ChangePassword 修改用户密码
func (s *UserService) ChangePassword(userID uint, req *ChangePasswordRequest) error {
// 1. 查询用户
var user model.User
if err := s.store.DB().First(&user, userID).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return errors.New("用户不存在")
}
return err
}
// 2. 验证旧密码
if err := bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(req.OldPassword)); err != nil {
return errors.New("原密码错误")
}
// 3. 验证新密码强度
if len(req.NewPassword) < 6 {
return errors.New("密码长度不能少于 6 位")
}
// 4. 加密新密码
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(req.NewPassword), bcrypt.DefaultCost)
if err != nil {
return err
}
// 5. 更新密码
user.PasswordHash = string(hashedPassword)
if err := s.store.DB().Save(&user).Error; err != nil {
return err
}
return nil
}
// GetUserByID 根据 ID 获取用户
func (s *UserService) GetUserByID(userID uint) (*model.User, error) {
var user model.User
if err := s.store.DB().First(&user, userID).Error; err != nil {
return nil, err
}
return &user, nil
}
// UpdateUser 更新用户信息
func (s *UserService) UpdateUser(userID uint, updates map[string]interface{}) (*model.User, error) {
var user model.User
if err := s.store.DB().First(&user, userID).Error; err != nil {
return nil, err
}
if err := s.store.DB().Model(&user).Updates(updates).Error; err != nil {
return nil, err
}
return &user, nil
}
// UpdateAdminProfile 更新管理员资料(仅允许 admin 用户调用)
func (s *UserService) UpdateAdminProfile(username, email, password string) error {
var user model.User
if err := s.store.DB().Where("role = ?", "admin").First(&user).Error; err != nil {
return errors.New("管理员账户不存在")
}
updates := make(map[string]interface{})
if username != "" && username != user.Username {
// 检查新用户名是否已被使用
var existing model.User
if err := s.store.DB().Where("username = ? AND role = ?", username, "admin").First(&existing).Error; err == nil {
return errors.New("用户名已存在")
}
updates["username"] = username
}
if email != "" && email != user.Email {
updates["email"] = email
}
if password != "" {
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
if err != nil {
return err
}
updates["password_hash"] = string(hashedPassword)
}
if len(updates) == 0 {
return nil // 没有需要更新的
}
return s.store.DB().Model(&user).Updates(updates).Error
}
// ResetAdminPassword 重置管理员密码(命令行工具使用)
func (s *UserService) ResetAdminPassword(newPassword string) error {
var user model.User
if err := s.store.DB().Where("role = ?", "admin").First(&user).Error; err != nil {
return errors.New("管理员账户不存在")
}
// 加密新密码
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(newPassword), bcrypt.DefaultCost)
if err != nil {
return err
}
return s.store.DB().Model(&user).Update("password_hash", string(hashedPassword)).Error
}