feat: 实现完整的板块级RBAC内容审核系统
- 新增站长/超级管理员/管理员/板块管理员四级角色体系 - 实现实时权限快照加载与细粒度权限校验 - 新增内容审核队列与前后端页面 - 重构用户权限管理与站点管理逻辑 - 新增评论/帖子审核状态与通知推送 - 优化前端权限控制与角色徽章展示 - 修正数据库迁移与默认值问题
This commit is contained in:
115
backend/service/actor.go
Normal file
115
backend/service/actor.go
Normal file
@@ -0,0 +1,115 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"github.com/freefire/jiang13-bbs/model"
|
||||
)
|
||||
|
||||
// 权限码:后台功能点。路由通过 RequirePerm 声明,
|
||||
// 板块管理员的板块范围由 Actor.BoardIDs 在业务层二次校验。
|
||||
const (
|
||||
PermUsers = "users" // 用户与权限管理(超管/站长)
|
||||
PermAnnouncements = "announcements" // 公告管理(管理员及以上)
|
||||
PermSettings = "settings" // 站点外观设置(超管/站长)
|
||||
PermModeration = "moderation" // 内容审核(任意管理角色,板块范围受限)
|
||||
)
|
||||
|
||||
// Actor 当前请求操作者的实时权限快照(每次后台请求从 DB 现取,
|
||||
// 不依赖 JWT 内的 role claim,角色/授权变更立即生效)
|
||||
type Actor struct {
|
||||
ID uint
|
||||
Username string
|
||||
Role model.Role
|
||||
BoardIDs []uint // 板块管理员被授权的板块;其他角色为空
|
||||
}
|
||||
|
||||
// IsStaff 是否管理团队成员
|
||||
func (a *Actor) IsStaff() bool {
|
||||
return a != nil && model.IsStaff(a.Role)
|
||||
}
|
||||
|
||||
// HasPerm 是否拥有某后台功能点
|
||||
func (a *Actor) HasPerm(p string) bool {
|
||||
if a == nil {
|
||||
return false
|
||||
}
|
||||
switch p {
|
||||
case PermUsers, PermSettings:
|
||||
return a.Role == model.RoleSuperAdmin || a.Role == model.RoleOwner
|
||||
case PermAnnouncements:
|
||||
return model.RoleLevel(a.Role) >= model.RoleLevel(model.RoleAdmin)
|
||||
case PermModeration:
|
||||
return a.IsStaff()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// CanModerateBoard 是否可管理指定板块的内容:
|
||||
// 管理员及以上不限板块;板块管理员仅限被授权板块
|
||||
func (a *Actor) CanModerateBoard(boardID uint) bool {
|
||||
if a == nil {
|
||||
return false
|
||||
}
|
||||
if model.RoleLevel(a.Role) >= model.RoleLevel(model.RoleAdmin) {
|
||||
return true
|
||||
}
|
||||
if a.Role != model.RoleBoardAdmin {
|
||||
return false
|
||||
}
|
||||
for _, id := range a.BoardIDs {
|
||||
if id == boardID {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// CanAssignRole 操作者能否把他人设置为目标角色(站长不可被授予,仅站长可授予超管)
|
||||
func (a *Actor) CanAssignRole(target model.Role) bool {
|
||||
if a == nil {
|
||||
return false
|
||||
}
|
||||
if target == model.RoleOwner {
|
||||
return false // 站长身份不通过授权产生
|
||||
}
|
||||
if target == model.RoleSuperAdmin {
|
||||
return a.Role == model.RoleOwner
|
||||
}
|
||||
return a.HasPerm(PermUsers)
|
||||
}
|
||||
|
||||
// LoadActor 读取用户实时角色与板块授权
|
||||
func (s *AuthService) LoadActor(id uint) (*Actor, error) {
|
||||
var u model.User
|
||||
if err := s.db.Select("id", "username", "role").First(&u, id).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
actor := &Actor{ID: u.ID, Username: u.Username, Role: u.Role, BoardIDs: []uint{}}
|
||||
if u.Role == model.RoleBoardAdmin {
|
||||
var ids []uint
|
||||
if err := s.db.Model(&model.UserBoard{}).
|
||||
Where("user_id = ?", id).
|
||||
Order("board_id ASC").
|
||||
Pluck("board_id", &ids).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
actor.BoardIDs = ids
|
||||
}
|
||||
return actor, nil
|
||||
}
|
||||
|
||||
// GetUserBoardIDs 读取用户被授权的板块 ID(供 /me 等场景)
|
||||
func (s *AuthService) GetUserBoardIDs(id uint) ([]uint, error) {
|
||||
var ids []uint
|
||||
err := s.db.Model(&model.UserBoard{}).
|
||||
Where("user_id = ?", id).Order("board_id ASC").Pluck("board_id", &ids).Error
|
||||
return ids, err
|
||||
}
|
||||
|
||||
// GetUserIDByUsername 按用户名查 ID(登录失败审计用),用户不存在返回 0
|
||||
func (s *AuthService) GetUserIDByUsername(username string) uint {
|
||||
var u model.User
|
||||
if err := s.db.Select("id").Where("username = ?", username).First(&u).Error; err != nil {
|
||||
return 0
|
||||
}
|
||||
return u.ID
|
||||
}
|
||||
Reference in New Issue
Block a user