完成租户登录
This commit is contained in:
@@ -14,18 +14,20 @@ var jwtSecret = []byte("yunzer_jwt_secret_key") // 在实际应用中应从配
|
||||
type Claims struct {
|
||||
UserID int `json:"user_id"`
|
||||
Username string `json:"username"`
|
||||
TenantId int `json:"tenant_id"` // 租户ID
|
||||
jwt.RegisteredClaims
|
||||
}
|
||||
|
||||
// GenerateToken 生成JWT token
|
||||
func GenerateToken(userID int, username string) (string, error) {
|
||||
func GenerateToken(userID int, username string, tenantId int) (string, error) {
|
||||
// 设置token过期时间
|
||||
expirationTime := time.Now().Add(24 * time.Hour) // 24小时后过期
|
||||
|
||||
// 创建claims
|
||||
claims := &Claims{
|
||||
UserID: userID,
|
||||
UserID: userID,
|
||||
Username: username,
|
||||
TenantId: tenantId,
|
||||
RegisteredClaims: jwt.RegisteredClaims{
|
||||
ExpiresAt: jwt.NewNumericDate(expirationTime),
|
||||
IssuedAt: jwt.NewNumericDate(time.Now()),
|
||||
@@ -63,4 +65,4 @@ func ParseToken(tokenString string) (*Claims, error) {
|
||||
}
|
||||
|
||||
return claims, nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,6 +69,18 @@ func UpdateMenu(menu *Menu) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// UpdateMenuStatus 更新菜单状态
|
||||
func UpdateMenuStatus(id int, status int8) error {
|
||||
o := orm.NewOrm()
|
||||
menu := Menu{Id: id}
|
||||
if err := o.Read(&menu); err != nil {
|
||||
return err
|
||||
}
|
||||
menu.Status = status
|
||||
_, err := o.Update(&menu, "Status")
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteMenu 删除菜单
|
||||
func DeleteMenu(id int) error {
|
||||
o := orm.NewOrm()
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/beego/beego/v2/client/orm"
|
||||
)
|
||||
|
||||
type Tenant struct {
|
||||
Id int `orm:"pk;auto" json:"id"`
|
||||
Name string `orm:"size(100)" json:"name"`
|
||||
Code string `orm:"size(50);unique" json:"code"`
|
||||
Owner string `orm:"size(50)" json:"owner"`
|
||||
Phone string `orm:"size(20);null" json:"phone"`
|
||||
Email string `orm:"size(100);null" json:"email"`
|
||||
Status string `orm:"size(20);default(enabled)" json:"status"` // enabled, disabled
|
||||
AuditStatus string `orm:"size(20);default(pending)" json:"audit_status"` // pending, approved, rejected
|
||||
AuditComment string `orm:"type(text);null" json:"audit_comment"`
|
||||
AuditBy string `orm:"size(50);null" json:"audit_by"`
|
||||
AuditTime *time.Time `orm:"null;type(datetime)" json:"audit_time"`
|
||||
Remark string `orm:"type(text);null" json:"remark"`
|
||||
CreateTime time.Time `orm:"auto_now_add;type(datetime)" json:"create_time"`
|
||||
UpdateTime time.Time `orm:"auto_now;type(datetime)" json:"update_time"`
|
||||
DeleteTime *time.Time `orm:"null;type(datetime)" json:"delete_time"`
|
||||
CreateBy string `orm:"size(50);null" json:"create_by"`
|
||||
UpdateBy string `orm:"size(50);null" json:"update_by"`
|
||||
}
|
||||
|
||||
// TableName 设置表名
|
||||
func (t *Tenant) TableName() string {
|
||||
return "yz_tenants"
|
||||
}
|
||||
|
||||
func init() {
|
||||
orm.RegisterModel(new(Tenant))
|
||||
}
|
||||
|
||||
// GetTenantList 获取所有租户(软删除:只返回未删除的)
|
||||
func GetTenantList() ([]Tenant, error) {
|
||||
o := orm.NewOrm()
|
||||
var tenants []Tenant
|
||||
// 使用原生 SQL 查询 delete_time IS NULL 的记录(更可靠)
|
||||
_, err := o.Raw("SELECT * FROM yz_tenants WHERE delete_time IS NULL ORDER BY id DESC").QueryRows(&tenants)
|
||||
return tenants, err
|
||||
}
|
||||
|
||||
// CreateTenant 新建租户
|
||||
func CreateTenant(tenant *Tenant) error {
|
||||
o := orm.NewOrm()
|
||||
_, err := o.Insert(tenant)
|
||||
return err
|
||||
}
|
||||
|
||||
// UpdateTenant 编辑租户(只能编辑未删除的)
|
||||
func UpdateTenant(id int, data map[string]interface{}) error {
|
||||
o := orm.NewOrm()
|
||||
// 先检查租户是否存在且未删除
|
||||
tenant := Tenant{}
|
||||
err := o.Raw("SELECT * FROM yz_tenants WHERE id = ? AND delete_time IS NULL", id).QueryRow(&tenant)
|
||||
if err == orm.ErrNoRows {
|
||||
return errors.New("租户不存在或已被删除")
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// 更新记录
|
||||
_, err = o.QueryTable(new(Tenant)).Filter("Id", id).Update(data)
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteTenant 软删除租户(设置 delete_time)
|
||||
func DeleteTenant(id int) error {
|
||||
o := orm.NewOrm()
|
||||
deleteTime := time.Now()
|
||||
_, err := o.QueryTable(new(Tenant)).Filter("Id", id).Update(orm.Params{"delete_time": deleteTime})
|
||||
return err
|
||||
}
|
||||
|
||||
// AuditTenant 审核租户(只能审核未删除的)
|
||||
func AuditTenant(id int, auditStatus, auditComment, auditBy string) error {
|
||||
o := orm.NewOrm()
|
||||
tenant := Tenant{}
|
||||
// 先检查租户是否存在且未删除
|
||||
err := o.Raw("SELECT * FROM yz_tenants WHERE id = ? AND delete_time IS NULL", id).QueryRow(&tenant)
|
||||
if err == orm.ErrNoRows {
|
||||
return errors.New("租户不存在或已被删除")
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
now := time.Now()
|
||||
tenant.AuditStatus = auditStatus
|
||||
tenant.AuditComment = auditComment
|
||||
tenant.AuditBy = auditBy
|
||||
tenant.AuditTime = &now
|
||||
|
||||
_, err = o.Update(&tenant, "AuditStatus", "AuditComment", "AuditBy", "AuditTime")
|
||||
return err
|
||||
}
|
||||
|
||||
// GetTenantById 根据ID获取租户详情(只返回未删除的)
|
||||
func GetTenantById(id int) (*Tenant, error) {
|
||||
o := orm.NewOrm()
|
||||
tenant := Tenant{}
|
||||
// 使用原生 SQL 查询,只返回未删除的记录
|
||||
err := o.Raw("SELECT * FROM yz_tenants WHERE id = ? AND delete_time IS NULL", id).QueryRow(&tenant)
|
||||
if err == orm.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
return &tenant, err
|
||||
}
|
||||
|
||||
// GetTenantByName 根据名称获取租户详情(只返回未删除的)
|
||||
func GetTenantByName(name string) (*Tenant, error) {
|
||||
o := orm.NewOrm()
|
||||
tenant := Tenant{}
|
||||
// 使用原生 SQL 查询,只返回未删除的记录
|
||||
err := o.Raw("SELECT * FROM yz_tenants WHERE name = ? AND delete_time IS NULL", name).QueryRow(&tenant)
|
||||
if err == orm.ErrNoRows {
|
||||
return nil, errors.New("租户不存在")
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &tenant, nil
|
||||
}
|
||||
+108
-42
@@ -16,7 +16,8 @@ import (
|
||||
// User 用户模型,增加Salt字段存储每个用户的唯一盐值
|
||||
type User struct {
|
||||
Id int `orm:"auto"`
|
||||
Username string `orm:"unique"`
|
||||
TenantId int `orm:"column(tenant_id);default(0)" json:"tenant_id"` // 租户ID
|
||||
Username string // 用户名不再全局唯一,而是在租户内唯一(tenant_id + username 的组合唯一)
|
||||
Password string // 存储加密后的密码
|
||||
Salt string // 存储该用户的唯一盐值
|
||||
Email string
|
||||
@@ -66,15 +67,14 @@ func verifyPassword(password, salt, storedHash string) bool {
|
||||
return hash == storedHash
|
||||
}
|
||||
|
||||
// ResetPassword 重置用户密码
|
||||
func ResetPassword(username, superPassword string) error {
|
||||
// ResetPassword 重置用户密码(支持租户模式)
|
||||
func ResetPassword(username, superPassword string, tenantId int) error {
|
||||
if superPassword != "Lzq920103" {
|
||||
return fmt.Errorf("超级密码错误")
|
||||
}
|
||||
|
||||
o := orm.NewOrm()
|
||||
user := &User{Username: username}
|
||||
err := o.Read(user, "Username")
|
||||
user, err := GetUserByUsername(username, tenantId)
|
||||
if err != nil {
|
||||
return fmt.Errorf("用户不存在: %v", err)
|
||||
}
|
||||
@@ -102,9 +102,9 @@ func ResetPassword(username, superPassword string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ChangePassword 修改用户密码
|
||||
func ChangePassword(username, oldPassword, newPassword string) error {
|
||||
user, err := GetUserByUsername(username)
|
||||
// ChangePassword 修改用户密码(支持租户模式)
|
||||
func ChangePassword(username, oldPassword, newPassword string, tenantId int) error {
|
||||
user, err := GetUserByUsername(username, tenantId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -124,22 +124,32 @@ func ChangePassword(username, oldPassword, newPassword string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// FindAllUsers 获取所有用户
|
||||
func FindAllUsers() []*User {
|
||||
// FindAllUsers 获取所有用户(支持按租户过滤)
|
||||
func FindAllUsers(tenantId int) []*User {
|
||||
o := orm.NewOrm()
|
||||
var users []*User
|
||||
_, err := o.QueryTable("yz_users").All(&users)
|
||||
if err != nil {
|
||||
return []*User{}
|
||||
if tenantId > 0 {
|
||||
// 按租户ID查询
|
||||
_, err := o.Raw("SELECT * FROM yz_users WHERE tenant_id = ?", tenantId).QueryRows(&users)
|
||||
if err != nil {
|
||||
return []*User{}
|
||||
}
|
||||
} else {
|
||||
// 查询所有用户
|
||||
_, err := o.QueryTable("yz_users").All(&users)
|
||||
if err != nil {
|
||||
return []*User{}
|
||||
}
|
||||
}
|
||||
return users
|
||||
}
|
||||
|
||||
// GetUserByUsername 根据用户名获取用户
|
||||
func GetUserByUsername(username string) (*User, error) {
|
||||
// GetUserByUsername 根据用户名获取用户(支持租户隔离)
|
||||
func GetUserByUsername(username string, tenantId int) (*User, error) {
|
||||
o := orm.NewOrm()
|
||||
user := &User{Username: username}
|
||||
err := o.Read(user, "Username")
|
||||
user := &User{}
|
||||
// 使用原生 SQL 查询,考虑租户ID
|
||||
err := o.Raw("SELECT * FROM yz_users WHERE username = ? AND tenant_id = ?", username, tenantId).QueryRow(user)
|
||||
if err == orm.ErrNoRows {
|
||||
return nil, errors.New("用户不存在")
|
||||
}
|
||||
@@ -149,24 +159,74 @@ func GetUserByUsername(username string) (*User, error) {
|
||||
return user, nil
|
||||
}
|
||||
|
||||
// ValidateUser 验证用户登录信息
|
||||
func ValidateUser(username, password string) (*User, error) {
|
||||
user, err := GetUserByUsername(username)
|
||||
// ValidateUser 验证用户登录信息(支持租户模式,根据租户名称)
|
||||
// 先验证租户是否存在且有效,再验证租户下的用户
|
||||
func ValidateUser(username, password string, tenantName string) (*User, error) {
|
||||
o := orm.NewOrm()
|
||||
|
||||
// 1. 根据租户名称查询租户(只查询未删除的)
|
||||
var tenant struct {
|
||||
Id int
|
||||
Status string
|
||||
DeleteTime interface{} // 使用 interface{} 来处理 NULL 值
|
||||
}
|
||||
err := o.Raw("SELECT id, status, delete_time FROM yz_tenants WHERE name = ? AND delete_time IS NULL", tenantName).QueryRow(&tenant)
|
||||
if err == orm.ErrNoRows {
|
||||
// 租户不存在(数据库中根本没有这个名称)
|
||||
return nil, errors.New("租户不存在")
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("查询租户失败: %v", err)
|
||||
}
|
||||
|
||||
// 检查租户是否被删除(软删除)
|
||||
if tenant.DeleteTime != nil {
|
||||
// delete_time 不为 NULL,说明已被删除
|
||||
return nil, errors.New("租户已被删除")
|
||||
}
|
||||
|
||||
// 检查租户状态
|
||||
if tenant.Status == "disabled" {
|
||||
return nil, errors.New("租户已被禁用")
|
||||
}
|
||||
|
||||
if tenant.Status != "enabled" {
|
||||
return nil, fmt.Errorf("租户状态异常: %s", tenant.Status)
|
||||
}
|
||||
|
||||
tenantId := tenant.Id
|
||||
|
||||
// 2. 获取租户下的用户
|
||||
user, err := GetUserByUsername(username, tenantId)
|
||||
if err != nil {
|
||||
// 用户不存在或查询失败
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 3. 验证密码
|
||||
if verifyPassword(password, user.Salt, user.Password) {
|
||||
return user, nil
|
||||
}
|
||||
return nil, errors.New("密码不正确")
|
||||
}
|
||||
|
||||
// AddUser 向数据库添加新用户(模型层核心方法)
|
||||
func AddUser(username, password, email, nickname, avatar string) (*User, error) {
|
||||
// 1. 检查用户是否已存在(避免用户名重复)
|
||||
existingUser, err := GetUserByUsername(username)
|
||||
// AddUser 向数据库添加新用户(模型层核心方法,支持租户模式)
|
||||
func AddUser(username, password, email, nickname, avatar string, tenantId int) (*User, error) {
|
||||
// 1. 验证租户是否存在且有效
|
||||
o := orm.NewOrm()
|
||||
var tenantExists bool
|
||||
err := o.Raw("SELECT EXISTS(SELECT 1 FROM yz_tenants WHERE id = ? AND delete_time IS NULL AND status = 'enabled')", tenantId).QueryRow(&tenantExists)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("验证租户失败: %v", err)
|
||||
}
|
||||
if !tenantExists {
|
||||
return nil, fmt.Errorf("租户不存在或已被禁用")
|
||||
}
|
||||
|
||||
// 2. 检查该租户下用户是否已存在(避免用户名重复,但不同租户可以有相同的用户名)
|
||||
existingUser, err := GetUserByUsername(username, tenantId)
|
||||
if err == nil && existingUser != nil {
|
||||
return nil, fmt.Errorf("用户名已存在")
|
||||
return nil, fmt.Errorf("该租户下用户名已存在")
|
||||
}
|
||||
if err != nil && err.Error() != "用户不存在" { // 排除"用户不存在"的正常错误
|
||||
return nil, fmt.Errorf("查询用户失败: %v", err)
|
||||
@@ -186,6 +246,7 @@ func AddUser(username, password, email, nickname, avatar string) (*User, error)
|
||||
|
||||
// 4. 构建用户对象
|
||||
user := &User{
|
||||
TenantId: tenantId,
|
||||
Username: username,
|
||||
Password: hashedPassword, // 存储加密后的密码
|
||||
Salt: salt, // 存储盐值(用于后续验证)
|
||||
@@ -194,8 +255,7 @@ func AddUser(username, password, email, nickname, avatar string) (*User, error)
|
||||
Avatar: avatar,
|
||||
}
|
||||
|
||||
// 5. 插入数据库
|
||||
o := orm.NewOrm()
|
||||
// 5. 插入数据库(使用之前定义的 o)
|
||||
_, err = o.Insert(user)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("数据库插入失败: %v", err)
|
||||
@@ -205,22 +265,25 @@ func AddUser(username, password, email, nickname, avatar string) (*User, error)
|
||||
return user, nil
|
||||
}
|
||||
|
||||
// UpdateUser 更新用户信息(模型层方法)
|
||||
func UpdateUser(id int, username, email, nickname, avatar string) (*User, error) {
|
||||
// 1. 根据ID查询用户是否存在
|
||||
// UpdateUser 更新用户信息(模型层方法,支持租户模式)
|
||||
func UpdateUser(id int, username, email, nickname, avatar string, tenantId int) (*User, error) {
|
||||
// 1. 根据ID和租户ID查询用户是否存在(确保只能更新自己租户下的用户)
|
||||
o := orm.NewOrm()
|
||||
user := &User{Id: id}
|
||||
err := o.Read(user)
|
||||
user := &User{}
|
||||
err := o.Raw("SELECT * FROM yz_users WHERE id = ? AND tenant_id = ?", id, tenantId).QueryRow(user)
|
||||
if err == orm.ErrNoRows {
|
||||
return nil, fmt.Errorf("用户不存在或不属于该租户")
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("用户不存在: %v", err)
|
||||
return nil, fmt.Errorf("查询用户失败: %v", err)
|
||||
}
|
||||
|
||||
// 2. 仅更新非空字段(避免覆盖原有值)
|
||||
if username != "" {
|
||||
// 若更新用户名,需检查新用户名是否已被占用
|
||||
existingUser, _ := GetUserByUsername(username)
|
||||
// 若更新用户名,需检查同一租户下新用户名是否已被占用
|
||||
existingUser, _ := GetUserByUsername(username, tenantId)
|
||||
if existingUser != nil && existingUser.Id != id {
|
||||
return nil, fmt.Errorf("用户名已被占用")
|
||||
return nil, fmt.Errorf("该租户下用户名已被占用")
|
||||
}
|
||||
user.Username = username
|
||||
}
|
||||
@@ -243,14 +306,17 @@ func UpdateUser(id int, username, email, nickname, avatar string) (*User, error)
|
||||
return user, nil
|
||||
}
|
||||
|
||||
// DeleteUser 根据ID删除用户(模型层方法)
|
||||
func DeleteUser(id int) error {
|
||||
// DeleteUser 根据ID删除用户(模型层方法,支持租户模式)
|
||||
func DeleteUser(id int, tenantId int) error {
|
||||
o := orm.NewOrm()
|
||||
// 先查询用户是否存在
|
||||
user := &User{Id: id}
|
||||
err := o.Read(user)
|
||||
// 先查询用户是否存在且属于指定租户
|
||||
user := &User{}
|
||||
err := o.Raw("SELECT * FROM yz_users WHERE id = ? AND tenant_id = ?", id, tenantId).QueryRow(user)
|
||||
if err == orm.ErrNoRows {
|
||||
return fmt.Errorf("用户不存在或不属于该租户")
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("用户不存在: %v", err)
|
||||
return fmt.Errorf("查询用户失败: %v", err)
|
||||
}
|
||||
|
||||
// 执行删除操作
|
||||
|
||||
Reference in New Issue
Block a user