kra/internal/biz/system/user.go

234 lines
7.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package system
import (
"context"
"encoding/json"
"errors"
"time"
"github.com/google/uuid"
"golang.org/x/crypto/bcrypt"
)
var (
ErrUserNotFound = errors.New("用户不存在")
ErrUserAlreadyExists = errors.New("用户名已注册")
ErrPasswordWrong = errors.New("密码错误")
ErrOldPasswordWrong = errors.New("原密码错误")
ErrUserNoAuthority = errors.New("该用户无此角色")
ErrDefaultRouterEmpty = errors.New("找不到默认路由,无法切换本角色")
)
// User 用户实体
type User struct {
ID uint
UUID uuid.UUID
Username string
Password string
NickName string
SideMode string
HeaderImg string
BaseColor string
AuthorityId uint
Phone string
Email string
Enable int
OriginSetting json.RawMessage
Authority *Authority
Authorities []*Authority
CreatedAt time.Time
UpdatedAt time.Time
}
// Authority 角色实体
type Authority struct {
AuthorityId uint
AuthorityName string
ParentId *uint
DefaultRouter string
}
// UserRepo 用户仓储接口
type UserRepo interface {
Create(ctx context.Context, user *User) error
Update(ctx context.Context, user *User) error
UpdateSelf(ctx context.Context, user *User) error
UpdateSelfSetting(ctx context.Context, id uint, setting json.RawMessage) error
Delete(ctx context.Context, id uint) error
FindByID(ctx context.Context, id uint) (*User, error)
FindByIDWithAuthorities(ctx context.Context, id uint) (*User, error)
FindByUUID(ctx context.Context, uuid string) (*User, error)
FindByUUIDWithAuthorities(ctx context.Context, uuid string) (*User, error)
FindByUsername(ctx context.Context, username string) (*User, error)
FindByUsernameWithAuthorities(ctx context.Context, username string) (*User, error)
List(ctx context.Context, page, pageSize int, filters map[string]string) ([]*User, int64, error)
UpdatePassword(ctx context.Context, id uint, password string) error
UpdateAuthorityID(ctx context.Context, id uint, authorityId uint) error
SetUserAuthorities(ctx context.Context, adminAuthorityID, userId uint, authorityIds []uint) error
CheckUserHasAuthority(ctx context.Context, userId, authorityId uint) (bool, error)
GetAuthorityMenuRouters(ctx context.Context, authorityId uint) ([]string, error)
GetAuthorityDefaultRouter(ctx context.Context, authorityId uint) (string, error)
}
// UserUsecase 用户用例
type UserUsecase struct {
repo UserRepo
}
// NewUserUsecase 创建用户用例
func NewUserUsecase(repo UserRepo) *UserUsecase {
return &UserUsecase{repo: repo}
}
// Register 用户注册
func (uc *UserUsecase) Register(ctx context.Context, user *User) (*User, error) {
// 检查用户名是否已存在
existing, _ := uc.repo.FindByUsername(ctx, user.Username)
if existing != nil {
return nil, ErrUserAlreadyExists
}
// 密码加密
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(user.Password), bcrypt.DefaultCost)
if err != nil {
return nil, err
}
user.Password = string(hashedPassword)
user.UUID = uuid.New()
if err := uc.repo.Create(ctx, user); err != nil {
return nil, err
}
return user, nil
}
// Login 用户登录预加载Authorities
func (uc *UserUsecase) Login(ctx context.Context, username, password string) (*User, error) {
user, err := uc.repo.FindByUsernameWithAuthorities(ctx, username)
if err != nil {
return nil, ErrUserNotFound
}
if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password)); err != nil {
return nil, ErrPasswordWrong
}
return user, nil
}
// ChangePassword 修改密码
func (uc *UserUsecase) ChangePassword(ctx context.Context, id uint, oldPassword, newPassword string) error {
user, err := uc.repo.FindByID(ctx, id)
if err != nil {
return ErrUserNotFound
}
if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(oldPassword)); err != nil {
return ErrOldPasswordWrong
}
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(newPassword), bcrypt.DefaultCost)
if err != nil {
return err
}
return uc.repo.UpdatePassword(ctx, id, string(hashedPassword))
}
// ResetPassword 重置密码
func (uc *UserUsecase) ResetPassword(ctx context.Context, id uint, newPassword string) error {
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(newPassword), bcrypt.DefaultCost)
if err != nil {
return err
}
return uc.repo.UpdatePassword(ctx, id, string(hashedPassword))
}
// GetUserInfo 获取用户信息预加载Authorities
func (uc *UserUsecase) GetUserInfo(ctx context.Context, uuid string) (*User, error) {
return uc.repo.FindByUUIDWithAuthorities(ctx, uuid)
}
// GetUserByID 通过ID获取用户
func (uc *UserUsecase) GetUserByID(ctx context.Context, id uint) (*User, error) {
return uc.repo.FindByID(ctx, id)
}
// FindUserById 通过ID获取用户GVA兼容
func (uc *UserUsecase) FindUserById(ctx context.Context, id uint) (*User, error) {
return uc.repo.FindByID(ctx, id)
}
// FindUserByUuid 通过UUID获取用户GVA兼容
func (uc *UserUsecase) FindUserByUuid(ctx context.Context, uuid string) (*User, error) {
return uc.repo.FindByUUID(ctx, uuid)
}
// GetUserList 获取用户列表
func (uc *UserUsecase) GetUserList(ctx context.Context, page, pageSize int, filters map[string]string) ([]*User, int64, error) {
return uc.repo.List(ctx, page, pageSize, filters)
}
// SetUserInfo 设置用户信息(管理员用)
func (uc *UserUsecase) SetUserInfo(ctx context.Context, user *User) error {
return uc.repo.Update(ctx, user)
}
// SetSelfInfo 设置自己的信息(用户用)
func (uc *UserUsecase) SetSelfInfo(ctx context.Context, user *User) error {
return uc.repo.UpdateSelf(ctx, user)
}
// SetSelfSetting 设置自己的配置
func (uc *UserUsecase) SetSelfSetting(ctx context.Context, id uint, setting json.RawMessage) error {
return uc.repo.UpdateSelfSetting(ctx, id, setting)
}
// DeleteUser 删除用户
func (uc *UserUsecase) DeleteUser(ctx context.Context, id uint) error {
return uc.repo.Delete(ctx, id)
}
// SetUserAuthority 设置用户角色(切换角色)
func (uc *UserUsecase) SetUserAuthority(ctx context.Context, id uint, authorityId uint) error {
// 检查用户是否拥有该角色
hasAuthority, err := uc.repo.CheckUserHasAuthority(ctx, id, authorityId)
if err != nil {
return err
}
if !hasAuthority {
return ErrUserNoAuthority
}
// 获取角色的默认路由
defaultRouter, err := uc.repo.GetAuthorityDefaultRouter(ctx, authorityId)
if err != nil {
return err
}
// 获取角色的菜单路由列表
menuRouters, err := uc.repo.GetAuthorityMenuRouters(ctx, authorityId)
if err != nil {
return err
}
// 检查默认路由是否在菜单中
hasMenu := false
for _, router := range menuRouters {
if router == defaultRouter {
hasMenu = true
break
}
}
if !hasMenu {
return ErrDefaultRouterEmpty
}
return uc.repo.UpdateAuthorityID(ctx, id, authorityId)
}
// SetUserAuthorities 设置用户多角色
func (uc *UserUsecase) SetUserAuthorities(ctx context.Context, adminAuthorityID, userId uint, authorityIds []uint) error {
return uc.repo.SetUserAuthorities(ctx, adminAuthorityID, userId, authorityIds)
}