优化平台端租户端

This commit is contained in:
2026-09-09 00:30:44 +08:00
parent 672c22d9b6
commit 34b2449462
20 changed files with 847 additions and 42 deletions
+249
View File
@@ -0,0 +1,249 @@
package controllers
import (
"encoding/json"
"io"
"strconv"
"strings"
"server/models"
"server/pkg/jwtutil"
beego "github.com/beego/beego/v2/server/web"
)
// BackendRoleController 租户端(backend)角色管理(yz_system_admin_role, cid=2)
// 角色按租户隔离:所有读写均以当前登录租户(JWT 中的 tenant_id)为边界,
// 租户仅能查看/管理自己名下的角色,无法越权访问其他租户数据。
type BackendRoleController struct {
beego.Controller
}
type backendRolePayload struct {
Name string `json:"name"`
Status *uint8 `json:"status"`
Rights interface{} `json:"rights"`
}
// currentTenantID 从 Bearer Token 解析当前登录租户 ID。
// 返回 (tid, true) 表示成功;失败时已写入 401/403 响应并返回 (0, false)。
func (c *BackendRoleController) currentTenantID() (uint64, bool) {
authHeader := c.Ctx.Request.Header.Get("Authorization")
if authHeader == "" {
c.Data["json"] = map[string]interface{}{"code": 401, "msg": "未登录"}
_ = c.ServeJSON()
return 0, false
}
authParts := strings.SplitN(authHeader, " ", 2)
if len(authParts) != 2 || authParts[0] != "Bearer" {
c.Data["json"] = map[string]interface{}{"code": 401, "msg": "认证信息格式错误"}
_ = c.ServeJSON()
return 0, false
}
claims, err := jwtutil.ParseToken(authParts[1])
if err != nil {
c.Data["json"] = map[string]interface{}{"code": 401, "msg": "无效的token"}
_ = c.ServeJSON()
return 0, false
}
if claims.UserType != "backend" && claims.UserType != "app" {
c.Data["json"] = map[string]interface{}{"code": 403, "msg": "无权访问"}
_ = c.ServeJSON()
return 0, false
}
if claims.TenantId <= 0 {
c.Data["json"] = map[string]interface{}{"code": 401, "msg": "租户信息缺失"}
_ = c.ServeJSON()
return 0, false
}
return uint64(claims.TenantId), true
}
// GetAllRoles 获取当前租户的角色列表
// GET /backend/allRoles
func (c *BackendRoleController) GetAllRoles() {
tid, ok := c.currentTenantID()
if !ok {
return
}
// 懒加载补齐当前租户的默认角色(租户管理员/部门负责人/员工)
models.EnsureDefaultTenantRoles(tid)
var rows []models.AdminRole
_, err := models.Orm.QueryTable(new(models.AdminRole)).
Filter("cid", 2).
Filter("tenant_id", tid).
OrderBy("-id").
All(&rows)
if err != nil {
c.Data["json"] = map[string]interface{}{"code": 500, "msg": "查询失败"}
_ = c.ServeJSON()
return
}
c.Data["json"] = map[string]interface{}{"code": 200, "msg": "success", "data": rows}
_ = c.ServeJSON()
}
// GetRoleByID 获取当前租户的角色详情
// GET /backend/roles/:id
func (c *BackendRoleController) GetRoleByID() {
tid, ok := c.currentTenantID()
if !ok {
return
}
idStr := c.Ctx.Input.Param(":id")
id, _ := strconv.ParseUint(idStr, 10, 64)
if id == 0 {
c.Data["json"] = map[string]interface{}{"code": 400, "msg": "id 不能为空"}
_ = c.ServeJSON()
return
}
var role models.AdminRole
if err := models.Orm.QueryTable(new(models.AdminRole)).
Filter("id", id).
Filter("cid", 2).
Filter("tenant_id", tid).
One(&role); err != nil {
c.Data["json"] = map[string]interface{}{"code": 404, "msg": "角色不存在"}
_ = c.ServeJSON()
return
}
c.Data["json"] = map[string]interface{}{"code": 200, "msg": "success", "data": role}
_ = c.ServeJSON()
}
// CreateRole 创建当前租户的角色
// POST /backend/roles
func (c *BackendRoleController) CreateRole() {
tid, ok := c.currentTenantID()
if !ok {
return
}
var p backendRolePayload
raw, _ := io.ReadAll(c.Ctx.Request.Body)
if err := json.Unmarshal(raw, &p); err != nil {
c.Data["json"] = map[string]interface{}{"code": 400, "msg": "参数错误"}
_ = c.ServeJSON()
return
}
p.Name = strings.TrimSpace(p.Name)
if p.Name == "" {
c.Data["json"] = map[string]interface{}{"code": 400, "msg": "name 不能为空"}
_ = c.ServeJSON()
return
}
status := uint8(1)
if p.Status != nil {
status = *p.Status
}
rights := normalizeRights(p.Rights)
role := &models.AdminRole{
TenantID: tid,
Cid: 2,
Name: p.Name,
Status: status,
Rights: rights,
}
id, err := models.Orm.Insert(role)
if err != nil {
c.Data["json"] = map[string]interface{}{"code": 500, "msg": "创建失败"}
_ = c.ServeJSON()
return
}
c.Data["json"] = map[string]interface{}{"code": 200, "msg": "success", "data": map[string]interface{}{"id": id}}
_ = c.ServeJSON()
}
// UpdateRole 更新当前租户的角色
// PUT /backend/roles/:id
func (c *BackendRoleController) UpdateRole() {
tid, ok := c.currentTenantID()
if !ok {
return
}
idStr := c.Ctx.Input.Param(":id")
id, _ := strconv.ParseUint(idStr, 10, 64)
if id == 0 {
c.Data["json"] = map[string]interface{}{"code": 400, "msg": "id 不能为空"}
_ = c.ServeJSON()
return
}
var p backendRolePayload
raw, _ := io.ReadAll(c.Ctx.Request.Body)
if err := json.Unmarshal(raw, &p); err != nil {
c.Data["json"] = map[string]interface{}{"code": 400, "msg": "参数错误"}
_ = c.ServeJSON()
return
}
update := map[string]interface{}{}
if strings.TrimSpace(p.Name) != "" {
update["name"] = strings.TrimSpace(p.Name)
}
if p.Status != nil {
update["status"] = *p.Status
}
if p.Rights != nil {
update["rights"] = normalizeRights(p.Rights)
}
if len(update) == 0 {
c.Data["json"] = map[string]interface{}{"code": 400, "msg": "无更新字段"}
_ = c.ServeJSON()
return
}
// 仅允许更新本租户名下的角色,防止越权改到其他租户
cnt, err := models.Orm.QueryTable(new(models.AdminRole)).
Filter("id", id).
Filter("cid", 2).
Filter("tenant_id", tid).
Update(update)
if err != nil {
c.Data["json"] = map[string]interface{}{"code": 500, "msg": "更新失败"}
_ = c.ServeJSON()
return
}
if cnt == 0 {
c.Data["json"] = map[string]interface{}{"code": 404, "msg": "角色不存在"}
_ = c.ServeJSON()
return
}
c.Data["json"] = map[string]interface{}{"code": 200, "msg": "success"}
_ = c.ServeJSON()
}
// DeleteRole 删除当前租户的角色
// DELETE /backend/roles/:id
func (c *BackendRoleController) DeleteRole() {
tid, ok := c.currentTenantID()
if !ok {
return
}
idStr := c.Ctx.Input.Param(":id")
id, _ := strconv.ParseUint(idStr, 10, 64)
if id == 0 {
c.Data["json"] = map[string]interface{}{"code": 400, "msg": "id 不能为空"}
_ = c.ServeJSON()
return
}
// 仅允许删除本租户名下的角色
cnt, err := models.Orm.QueryTable(new(models.AdminRole)).
Filter("id", id).
Filter("cid", 2).
Filter("tenant_id", tid).
Delete()
if err != nil {
c.Data["json"] = map[string]interface{}{"code": 500, "msg": "删除失败"}
_ = c.ServeJSON()
return
}
if cnt == 0 {
c.Data["json"] = map[string]interface{}{"code": 404, "msg": "角色不存在"}
_ = c.ServeJSON()
return
}
c.Data["json"] = map[string]interface{}{"code": 200, "msg": "success"}
_ = c.ServeJSON()
}