Initial commit
This commit is contained in:
@@ -0,0 +1,221 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
|
||||
"git.zkcoi.com/zkcoi/meshray/internal/model"
|
||||
"git.zkcoi.com/zkcoi/meshray/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
|
||||
}
|
||||
Reference in New Issue
Block a user