任务三

This commit is contained in:
Yvan 2026-01-07 14:02:53 +08:00
parent 7df0450b1e
commit 03252d34e1
6 changed files with 955 additions and 0 deletions

View File

@ -50,6 +50,9 @@ type CasbinRepo interface {
UpdateCasbinApi(oldPath, newPath, oldMethod, newMethod string) error UpdateCasbinApi(oldPath, newPath, oldMethod, newMethod string) error
GetPolicyPathByAuthorityId(authorityId uint) []CasbinRule GetPolicyPathByAuthorityId(authorityId uint) []CasbinRule
FreshCasbin() error FreshCasbin() error
AddPolicies(rules [][]string) error
UpdateCasbin(adminAuthorityID, authorityId uint, casbinInfos []CasbinRule) error
RemoveFilteredPolicy(authorityId string) error
} }
// ApiUsecase API用例 // ApiUsecase API用例

View File

@ -0,0 +1,361 @@
package system
import (
"context"
"errors"
"strconv"
)
var (
ErrAuthorityExists = errors.New("存在相同角色id")
ErrAuthorityNotFound = errors.New("该角色不存在")
ErrAuthorityHasUsers = errors.New("此角色有用户正在使用禁止删除")
ErrAuthorityHasChildren = errors.New("此角色存在子角色不允许删除")
ErrAuthorityIDInvalid = errors.New("您提交的角色ID不合法")
)
// AuthorityFull 完整角色实体(包含关联)
type AuthorityFull struct {
Authority
DataAuthorityId []*Authority
Children []*AuthorityFull
SysBaseMenus []*BaseMenu
}
// CasbinInfo Casbin规则信息
type CasbinInfo struct {
Path string
Method string
}
// DefaultCasbin 默认Casbin规则
func DefaultCasbin() []CasbinInfo {
return []CasbinInfo{
{Path: "/menu/getMenu", Method: "POST"},
{Path: "/jwt/jsonInBlacklist", Method: "POST"},
{Path: "/base/login", Method: "POST"},
{Path: "/user/changePassword", Method: "POST"},
{Path: "/user/setUserAuthority", Method: "POST"},
{Path: "/user/getUserInfo", Method: "GET"},
{Path: "/user/setSelfInfo", Method: "PUT"},
{Path: "/fileUploadAndDownload/upload", Method: "POST"},
{Path: "/sysDictionary/findSysDictionary", Method: "GET"},
}
}
// DefaultMenu 默认菜单
func DefaultMenu() []*BaseMenu {
return []*BaseMenu{{
ID: 1,
ParentId: 0,
Path: "dashboard",
Name: "dashboard",
Component: "view/dashboard/index.vue",
Sort: 1,
Title: "仪表盘",
Icon: "setting",
}}
}
// AuthorityRepo 角色仓储接口
type AuthorityRepo interface {
Create(ctx context.Context, auth *Authority) error
Update(ctx context.Context, auth *Authority) error
Delete(ctx context.Context, authorityId uint) error
FindByID(ctx context.Context, authorityId uint) (*Authority, error)
FindByIDWithDataAuthority(ctx context.Context, authorityId uint) (*AuthorityFull, error)
FindByParentID(ctx context.Context, parentId uint) ([]*AuthorityFull, error)
FindChildren(ctx context.Context, authorityId uint) ([]*AuthorityFull, error)
HasUsers(ctx context.Context, authorityId uint) (bool, error)
HasChildren(ctx context.Context, authorityId uint) (bool, error)
GetParentAuthorityID(ctx context.Context, authorityId uint) (uint, error)
SetDataAuthority(ctx context.Context, authorityId uint, dataAuthorityIds []uint) error
SetMenuAuthority(ctx context.Context, authorityId uint, menuIds []uint) error
GetMenuIds(ctx context.Context, authorityId uint) ([]uint, error)
CopyAuthorityBtns(ctx context.Context, oldAuthorityId, newAuthorityId uint) error
DeleteAuthorityRelations(ctx context.Context, authorityId uint) error
}
// AuthorityUsecase 角色用例
type AuthorityUsecase struct {
repo AuthorityRepo
casbinRepo CasbinRepo
useStrictAuth bool
}
// NewAuthorityUsecase 创建角色用例
func NewAuthorityUsecase(repo AuthorityRepo, casbinRepo CasbinRepo, useStrictAuth bool) *AuthorityUsecase {
return &AuthorityUsecase{
repo: repo,
casbinRepo: casbinRepo,
useStrictAuth: useStrictAuth,
}
}
// CreateAuthority 创建角色
func (uc *AuthorityUsecase) CreateAuthority(ctx context.Context, auth *Authority) (*Authority, error) {
// 检查是否存在相同角色ID
existing, _ := uc.repo.FindByID(ctx, auth.AuthorityId)
if existing != nil {
return nil, ErrAuthorityExists
}
// 创建角色
if err := uc.repo.Create(ctx, auth); err != nil {
return nil, err
}
// 设置默认菜单
defaultMenus := DefaultMenu()
menuIds := make([]uint, len(defaultMenus))
for i, m := range defaultMenus {
menuIds[i] = m.ID
}
if err := uc.repo.SetMenuAuthority(ctx, auth.AuthorityId, menuIds); err != nil {
return nil, err
}
// 添加默认Casbin规则
casbinInfos := DefaultCasbin()
rules := make([][]string, len(casbinInfos))
for i, v := range casbinInfos {
rules[i] = []string{uintToStr(auth.AuthorityId), v.Path, v.Method}
}
if err := uc.casbinRepo.AddPolicies(rules); err != nil {
return nil, err
}
return auth, nil
}
// CopyAuthority 复制角色
func (uc *AuthorityUsecase) CopyAuthority(ctx context.Context, adminAuthorityID, oldAuthorityId uint, newAuth *Authority) (*Authority, error) {
// 检查新角色ID是否已存在
existing, _ := uc.repo.FindByID(ctx, newAuth.AuthorityId)
if existing != nil {
return nil, ErrAuthorityExists
}
// 获取旧角色的菜单
menuIds, err := uc.repo.GetMenuIds(ctx, oldAuthorityId)
if err != nil {
return nil, err
}
// 创建新角色
if err := uc.repo.Create(ctx, newAuth); err != nil {
return nil, err
}
// 复制菜单权限
if err := uc.repo.SetMenuAuthority(ctx, newAuth.AuthorityId, menuIds); err != nil {
return nil, err
}
// 复制按钮权限
if err := uc.repo.CopyAuthorityBtns(ctx, oldAuthorityId, newAuth.AuthorityId); err != nil {
return nil, err
}
// 复制Casbin规则
paths := uc.casbinRepo.GetPolicyPathByAuthorityId(oldAuthorityId)
if err := uc.casbinRepo.UpdateCasbin(adminAuthorityID, newAuth.AuthorityId, paths); err != nil {
_ = uc.DeleteAuthority(ctx, newAuth.AuthorityId)
return nil, err
}
return newAuth, nil
}
// UpdateAuthority 更新角色
func (uc *AuthorityUsecase) UpdateAuthority(ctx context.Context, auth *Authority) (*Authority, error) {
existing, err := uc.repo.FindByID(ctx, auth.AuthorityId)
if err != nil {
return nil, errors.New("查询角色数据失败")
}
if existing == nil {
return nil, ErrAuthorityNotFound
}
if err := uc.repo.Update(ctx, auth); err != nil {
return nil, err
}
return auth, nil
}
// DeleteAuthority 删除角色
func (uc *AuthorityUsecase) DeleteAuthority(ctx context.Context, authorityId uint) error {
// 检查角色是否存在
existing, err := uc.repo.FindByID(ctx, authorityId)
if err != nil || existing == nil {
return ErrAuthorityNotFound
}
// 检查是否有用户使用此角色
hasUsers, err := uc.repo.HasUsers(ctx, authorityId)
if err != nil {
return err
}
if hasUsers {
return ErrAuthorityHasUsers
}
// 检查是否有子角色
hasChildren, err := uc.repo.HasChildren(ctx, authorityId)
if err != nil {
return err
}
if hasChildren {
return ErrAuthorityHasChildren
}
// 删除关联关系
if err := uc.repo.DeleteAuthorityRelations(ctx, authorityId); err != nil {
return err
}
// 删除角色
if err := uc.repo.Delete(ctx, authorityId); err != nil {
return err
}
// 删除Casbin规则
uc.casbinRepo.RemoveFilteredPolicy(uintToStr(authorityId))
return nil
}
// GetAuthorityInfoList 获取角色列表(树形)
func (uc *AuthorityUsecase) GetAuthorityInfoList(ctx context.Context, authorityID uint) ([]*AuthorityFull, error) {
auth, err := uc.repo.FindByID(ctx, authorityID)
if err != nil {
return nil, err
}
var authorities []*AuthorityFull
if uc.useStrictAuth {
if auth.ParentId == nil || *auth.ParentId == 0 {
// 顶级角色可以修改自己的权限和以下权限
authFull, err := uc.repo.FindByIDWithDataAuthority(ctx, authorityID)
if err != nil {
return nil, err
}
authorities = []*AuthorityFull{authFull}
} else {
// 非顶级角色只能修改以下权限
authorities, err = uc.repo.FindByParentID(ctx, authorityID)
if err != nil {
return nil, err
}
}
} else {
authorities, err = uc.repo.FindByParentID(ctx, 0)
if err != nil {
return nil, err
}
}
// 递归获取子角色
for i := range authorities {
if err := uc.findChildrenAuthority(ctx, authorities[i]); err != nil {
return nil, err
}
}
return authorities, nil
}
func (uc *AuthorityUsecase) findChildrenAuthority(ctx context.Context, authority *AuthorityFull) error {
children, err := uc.repo.FindChildren(ctx, authority.AuthorityId)
if err != nil {
return err
}
authority.Children = children
for i := range authority.Children {
if err := uc.findChildrenAuthority(ctx, authority.Children[i]); err != nil {
return err
}
}
return nil
}
// GetStructAuthorityList 获取角色ID列表包含子角色
func (uc *AuthorityUsecase) GetStructAuthorityList(ctx context.Context, authorityID uint) ([]uint, error) {
auth, err := uc.repo.FindByID(ctx, authorityID)
if err != nil {
return nil, err
}
var list []uint
children, err := uc.repo.FindChildren(ctx, authorityID)
if err != nil {
return nil, err
}
for _, child := range children {
list = append(list, child.AuthorityId)
childList, err := uc.GetStructAuthorityList(ctx, child.AuthorityId)
if err == nil {
list = append(list, childList...)
}
}
if auth.ParentId == nil || *auth.ParentId == 0 {
list = append(list, authorityID)
}
return list, nil
}
// CheckAuthorityIDAuth 检查角色ID权限
func (uc *AuthorityUsecase) CheckAuthorityIDAuth(ctx context.Context, authorityID, targetID uint) error {
if !uc.useStrictAuth {
return nil
}
authIDs, err := uc.GetStructAuthorityList(ctx, authorityID)
if err != nil {
return err
}
for _, id := range authIDs {
if id == targetID {
return nil
}
}
return ErrAuthorityIDInvalid
}
// GetAuthorityInfo 获取角色信息
func (uc *AuthorityUsecase) GetAuthorityInfo(ctx context.Context, authorityId uint) (*AuthorityFull, error) {
return uc.repo.FindByIDWithDataAuthority(ctx, authorityId)
}
// SetDataAuthority 设置角色资源权限
func (uc *AuthorityUsecase) SetDataAuthority(ctx context.Context, adminAuthorityID uint, authorityId uint, dataAuthorityIds []uint) error {
// 检查权限
checkIDs := append([]uint{authorityId}, dataAuthorityIds...)
for _, id := range checkIDs {
if err := uc.CheckAuthorityIDAuth(ctx, adminAuthorityID, id); err != nil {
return err
}
}
return uc.repo.SetDataAuthority(ctx, authorityId, dataAuthorityIds)
}
// SetMenuAuthority 设置角色菜单权限
func (uc *AuthorityUsecase) SetMenuAuthority(ctx context.Context, authorityId uint, menuIds []uint) error {
return uc.repo.SetMenuAuthority(ctx, authorityId, menuIds)
}
// GetParentAuthorityID 获取父角色ID
func (uc *AuthorityUsecase) GetParentAuthorityID(ctx context.Context, authorityId uint) (uint, error) {
return uc.repo.GetParentAuthorityID(ctx, authorityId)
}
// 辅助函数
func uintToStr(n uint) string {
return strconv.FormatUint(uint64(n), 10)
}

View File

@ -67,11 +67,13 @@ type MenuRepo interface {
UpdateBaseMenu(ctx context.Context, menu *BaseMenu) error UpdateBaseMenu(ctx context.Context, menu *BaseMenu) error
DeleteBaseMenu(ctx context.Context, id uint) error DeleteBaseMenu(ctx context.Context, id uint) error
FindBaseMenuByID(ctx context.Context, id uint) (*BaseMenu, error) FindBaseMenuByID(ctx context.Context, id uint) (*BaseMenu, error)
FindBaseMenuByName(ctx context.Context, name string) (*BaseMenu, error)
FindAllBaseMenus(ctx context.Context) ([]*BaseMenu, error) FindAllBaseMenus(ctx context.Context) ([]*BaseMenu, error)
FindBaseMenusByIds(ctx context.Context, ids []string) ([]*BaseMenu, error) FindBaseMenusByIds(ctx context.Context, ids []string) ([]*BaseMenu, error)
FindAuthorityMenuIds(ctx context.Context, authorityId uint) ([]string, error) FindAuthorityMenuIds(ctx context.Context, authorityId uint) ([]string, error)
FindAuthorityBtns(ctx context.Context, authorityId uint) ([]*AuthorityBtn, error) FindAuthorityBtns(ctx context.Context, authorityId uint) ([]*AuthorityBtn, error)
SetMenuAuthority(ctx context.Context, authorityId uint, menuIds []uint) error SetMenuAuthority(ctx context.Context, authorityId uint, menuIds []uint) error
CheckMenuInAuthority(ctx context.Context, authorityId uint, menuName string) (bool, error)
} }
// MenuUsecase 菜单用例 // MenuUsecase 菜单用例
@ -291,3 +293,18 @@ func (uc *MenuUsecase) GetMenuAuthority(ctx context.Context, authorityId uint) (
} }
return menus, nil return menus, nil
} }
// UserAuthorityDefaultRouter 用户角色默认路由检查
// 如果用户的默认路由不在其权限菜单中则设置为404
func (uc *MenuUsecase) UserAuthorityDefaultRouter(ctx context.Context, authorityId uint, defaultRouter string) string {
if defaultRouter == "" {
return "404"
}
// 检查默认路由是否在用户的权限菜单中
exists, err := uc.repo.CheckMenuInAuthority(ctx, authorityId, defaultRouter)
if err != nil || !exists {
return "404"
}
return defaultRouter
}

View File

@ -0,0 +1,269 @@
package system
import (
"context"
"errors"
"kra/internal/biz/system"
"kra/internal/data/model"
"kra/internal/data/query"
"gorm.io/gorm"
)
type authorityRepo struct {
db *gorm.DB
}
// NewAuthorityRepo 创建角色仓储
func NewAuthorityRepo(db *gorm.DB) system.AuthorityRepo {
return &authorityRepo{db: db}
}
func (r *authorityRepo) Create(ctx context.Context, auth *system.Authority) error {
m := &model.SysAuthority{
AuthorityID: int64(auth.AuthorityId),
AuthorityName: &auth.AuthorityName,
DefaultRouter: &auth.DefaultRouter,
}
if auth.ParentId != nil {
parentId := int64(*auth.ParentId)
m.ParentID = &parentId
}
return r.db.WithContext(ctx).Create(m).Error
}
func (r *authorityRepo) Update(ctx context.Context, auth *system.Authority) error {
updates := map[string]any{
"authority_name": auth.AuthorityName,
"default_router": auth.DefaultRouter,
}
if auth.ParentId != nil {
updates["parent_id"] = *auth.ParentId
}
return r.db.WithContext(ctx).Model(&model.SysAuthority{}).
Where("authority_id = ?", auth.AuthorityId).
Updates(updates).Error
}
func (r *authorityRepo) Delete(ctx context.Context, authorityId uint) error {
return r.db.WithContext(ctx).Unscoped().
Where("authority_id = ?", authorityId).
Delete(&model.SysAuthority{}).Error
}
func (r *authorityRepo) FindByID(ctx context.Context, authorityId uint) (*system.Authority, error) {
m, err := query.SysAuthority.WithContext(ctx).
Where(query.SysAuthority.AuthorityID.Eq(int64(authorityId))).First()
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil
}
return nil, err
}
return toBizAuthority(m), nil
}
func (r *authorityRepo) FindByIDWithDataAuthority(ctx context.Context, authorityId uint) (*system.AuthorityFull, error) {
m, err := query.SysAuthority.WithContext(ctx).
Where(query.SysAuthority.AuthorityID.Eq(int64(authorityId))).First()
if err != nil {
return nil, err
}
// 获取数据权限
var dataAuthIds []model.SysDataAuthorityID
r.db.WithContext(ctx).Where("sys_authority_authority_id = ?", authorityId).Find(&dataAuthIds)
var dataAuthorities []*system.Authority
for _, da := range dataAuthIds {
auth, _ := r.FindByID(ctx, uint(da.DataAuthorityIDAuthorityID))
if auth != nil {
dataAuthorities = append(dataAuthorities, auth)
}
}
return &system.AuthorityFull{
Authority: *toBizAuthority(m),
DataAuthorityId: dataAuthorities,
}, nil
}
func (r *authorityRepo) FindByParentID(ctx context.Context, parentId uint) ([]*system.AuthorityFull, error) {
list, err := query.SysAuthority.WithContext(ctx).
Where(query.SysAuthority.ParentID.Eq(int64(parentId))).Find()
if err != nil {
return nil, err
}
result := make([]*system.AuthorityFull, len(list))
for i, m := range list {
// 获取数据权限
var dataAuthIds []model.SysDataAuthorityID
r.db.WithContext(ctx).Where("sys_authority_authority_id = ?", m.AuthorityID).Find(&dataAuthIds)
var dataAuthorities []*system.Authority
for _, da := range dataAuthIds {
auth, _ := r.FindByID(ctx, uint(da.DataAuthorityIDAuthorityID))
if auth != nil {
dataAuthorities = append(dataAuthorities, auth)
}
}
result[i] = &system.AuthorityFull{
Authority: *toBizAuthority(m),
DataAuthorityId: dataAuthorities,
}
}
return result, nil
}
func (r *authorityRepo) FindChildren(ctx context.Context, authorityId uint) ([]*system.AuthorityFull, error) {
return r.FindByParentID(ctx, authorityId)
}
func (r *authorityRepo) HasUsers(ctx context.Context, authorityId uint) (bool, error) {
var count int64
err := r.db.WithContext(ctx).Model(&model.SysUserAuthority{}).
Where("sys_authority_authority_id = ?", authorityId).Count(&count).Error
return count > 0, err
}
func (r *authorityRepo) HasChildren(ctx context.Context, authorityId uint) (bool, error) {
count, err := query.SysAuthority.WithContext(ctx).
Where(query.SysAuthority.ParentID.Eq(int64(authorityId))).Count()
return count > 0, err
}
func (r *authorityRepo) GetParentAuthorityID(ctx context.Context, authorityId uint) (uint, error) {
m, err := query.SysAuthority.WithContext(ctx).
Where(query.SysAuthority.AuthorityID.Eq(int64(authorityId))).First()
if err != nil {
return 0, err
}
if m.ParentID == nil {
return 0, nil
}
return uint(*m.ParentID), nil
}
func (r *authorityRepo) SetDataAuthority(ctx context.Context, authorityId uint, dataAuthorityIds []uint) error {
return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
// 删除旧的数据权限
if err := tx.Where("sys_authority_authority_id = ?", authorityId).
Delete(&model.SysDataAuthorityID{}).Error; err != nil {
return err
}
// 创建新的数据权限
for _, daId := range dataAuthorityIds {
da := &model.SysDataAuthorityID{
SysAuthorityAuthorityID: int64(authorityId),
DataAuthorityIDAuthorityID: int64(daId),
}
if err := tx.Create(da).Error; err != nil {
return err
}
}
return nil
})
}
func (r *authorityRepo) SetMenuAuthority(ctx context.Context, authorityId uint, menuIds []uint) error {
return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
// 删除旧的菜单权限
if err := tx.Where("sys_authority_authority_id = ?", authorityId).
Delete(&model.SysAuthorityMenu{}).Error; err != nil {
return err
}
// 创建新的菜单权限
for _, menuId := range menuIds {
am := &model.SysAuthorityMenu{
SysAuthorityAuthorityID: int64(authorityId),
SysBaseMenuID: int64(menuId),
}
if err := tx.Create(am).Error; err != nil {
return err
}
}
return nil
})
}
func (r *authorityRepo) GetMenuIds(ctx context.Context, authorityId uint) ([]uint, error) {
var menus []model.SysAuthorityMenu
if err := r.db.WithContext(ctx).Where("sys_authority_authority_id = ?", authorityId).
Find(&menus).Error; err != nil {
return nil, err
}
ids := make([]uint, len(menus))
for i, m := range menus {
ids[i] = uint(m.SysBaseMenuID)
}
return ids, nil
}
func (r *authorityRepo) CopyAuthorityBtns(ctx context.Context, oldAuthorityId, newAuthorityId uint) error {
var btns []model.SysAuthorityBtn
if err := r.db.WithContext(ctx).Where("authority_id = ?", oldAuthorityId).
Find(&btns).Error; err != nil {
return err
}
if len(btns) == 0 {
return nil
}
newAuthorityIdInt64 := int64(newAuthorityId)
for i := range btns {
btns[i].AuthorityID = &newAuthorityIdInt64
}
return r.db.WithContext(ctx).Create(&btns).Error
}
func (r *authorityRepo) DeleteAuthorityRelations(ctx context.Context, authorityId uint) error {
return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
// 删除菜单权限
if err := tx.Where("sys_authority_authority_id = ?", authorityId).
Delete(&model.SysAuthorityMenu{}).Error; err != nil {
return err
}
// 删除数据权限
if err := tx.Where("sys_authority_authority_id = ?", authorityId).
Delete(&model.SysDataAuthorityID{}).Error; err != nil {
return err
}
// 删除用户角色关联
if err := tx.Where("sys_authority_authority_id = ?", authorityId).
Delete(&model.SysUserAuthority{}).Error; err != nil {
return err
}
// 删除按钮权限
if err := tx.Where("authority_id = ?", authorityId).
Delete(&model.SysAuthorityBtn{}).Error; err != nil {
return err
}
return nil
})
}
// 转换函数
func toBizAuthority(m *model.SysAuthority) *system.Authority {
auth := &system.Authority{
AuthorityId: uint(m.AuthorityID),
AuthorityName: safeString(m.AuthorityName),
DefaultRouter: safeString(m.DefaultRouter),
}
if m.ParentID != nil {
parentId := uint(*m.ParentID)
auth.ParentId = &parentId
}
return auth
}

View File

@ -249,6 +249,40 @@ func (r *menuRepo) FindBaseMenuByID(ctx context.Context, id uint) (*system.BaseM
return toBizBaseMenu(&menu, params, btns), nil return toBizBaseMenu(&menu, params, btns), nil
} }
// FindBaseMenuByName 根据名称获取基础菜单
func (r *menuRepo) FindBaseMenuByName(ctx context.Context, name string) (*system.BaseMenu, error) {
var menu model.SysBaseMenu
if err := r.db.WithContext(ctx).Where("name = ?", name).First(&menu).Error; err != nil {
return nil, err
}
return toBizBaseMenu(&menu, nil, nil), nil
}
// CheckMenuInAuthority 检查菜单是否在角色权限中
func (r *menuRepo) CheckMenuInAuthority(ctx context.Context, authorityId uint, menuName string) (bool, error) {
// 获取角色的菜单ID列表
var menuIds []string
if err := r.db.WithContext(ctx).Model(&model.SysAuthorityMenu{}).
Where("sys_authority_authority_id = ?", authorityId).
Pluck("sys_base_menu_id", &menuIds).Error; err != nil {
return false, err
}
if len(menuIds) == 0 {
return false, nil
}
// 检查菜单名称是否在这些菜单中
var count int64
if err := r.db.WithContext(ctx).Model(&model.SysBaseMenu{}).
Where("name = ? AND id IN (?)", menuName, menuIds).
Count(&count).Error; err != nil {
return false, err
}
return count > 0, nil
}
// FindAllBaseMenus 获取所有基础菜单 // FindAllBaseMenus 获取所有基础菜单
func (r *menuRepo) FindAllBaseMenus(ctx context.Context) ([]*system.BaseMenu, error) { func (r *menuRepo) FindAllBaseMenus(ctx context.Context) ([]*system.BaseMenu, error) {
var menus []model.SysBaseMenu var menus []model.SysBaseMenu

View File

@ -0,0 +1,271 @@
package system
import (
"context"
"kra/internal/biz/system"
"kra/internal/server/middleware"
"github.com/go-kratos/kratos/v2/errors"
"github.com/go-kratos/kratos/v2/transport/http"
)
// AuthorityService 角色服务
type AuthorityService struct {
uc *system.AuthorityUsecase
casbin system.CasbinRepo
}
// NewAuthorityService 创建角色服务
func NewAuthorityService(uc *system.AuthorityUsecase, casbin system.CasbinRepo) *AuthorityService {
return &AuthorityService{
uc: uc,
casbin: casbin,
}
}
// AuthorityInfo 角色信息
type AuthorityFullInfo struct {
AuthorityId uint `json:"authorityId"`
AuthorityName string `json:"authorityName"`
ParentId *uint `json:"parentId,omitempty"`
DefaultRouter string `json:"defaultRouter"`
DataAuthorityId []*AuthorityInfo `json:"dataAuthorityId,omitempty"`
Children []*AuthorityFullInfo `json:"children,omitempty"`
}
// CreateAuthorityRequest 创建角色请求
type CreateAuthorityRequest struct {
AuthorityId uint `json:"authorityId"`
AuthorityName string `json:"authorityName"`
ParentId uint `json:"parentId"`
DefaultRouter string `json:"defaultRouter"`
}
// CreateAuthority 创建角色
func (s *AuthorityService) CreateAuthority(ctx context.Context, req *CreateAuthorityRequest) (*AuthorityFullInfo, error) {
auth := &system.Authority{
AuthorityId: req.AuthorityId,
AuthorityName: req.AuthorityName,
DefaultRouter: req.DefaultRouter,
}
if req.ParentId != 0 {
auth.ParentId = &req.ParentId
}
result, err := s.uc.CreateAuthority(ctx, auth)
if err != nil {
return nil, err
}
// 刷新Casbin
_ = s.casbin.FreshCasbin()
return toAuthorityFullInfo(result), nil
}
// CopyAuthorityRequest 复制角色请求
type CopyAuthorityRequest struct {
Authority CreateAuthorityRequest `json:"authority"`
OldAuthorityId uint `json:"oldAuthorityId"`
}
// CopyAuthority 复制角色
func (s *AuthorityService) CopyAuthority(ctx context.Context, adminAuthorityID uint, req *CopyAuthorityRequest) (*AuthorityFullInfo, error) {
newAuth := &system.Authority{
AuthorityId: req.Authority.AuthorityId,
AuthorityName: req.Authority.AuthorityName,
DefaultRouter: req.Authority.DefaultRouter,
}
if req.Authority.ParentId != 0 {
newAuth.ParentId = &req.Authority.ParentId
}
result, err := s.uc.CopyAuthority(ctx, adminAuthorityID, req.OldAuthorityId, newAuth)
if err != nil {
return nil, err
}
return toAuthorityFullInfo(result), nil
}
// UpdateAuthorityRequest 更新角色请求
type UpdateAuthorityRequest struct {
AuthorityId uint `json:"authorityId"`
AuthorityName string `json:"authorityName"`
ParentId uint `json:"parentId"`
DefaultRouter string `json:"defaultRouter"`
}
// UpdateAuthority 更新角色
func (s *AuthorityService) UpdateAuthority(ctx context.Context, req *UpdateAuthorityRequest) (*AuthorityFullInfo, error) {
auth := &system.Authority{
AuthorityId: req.AuthorityId,
AuthorityName: req.AuthorityName,
DefaultRouter: req.DefaultRouter,
}
if req.ParentId != 0 {
auth.ParentId = &req.ParentId
}
result, err := s.uc.UpdateAuthority(ctx, auth)
if err != nil {
return nil, err
}
return toAuthorityFullInfo(result), nil
}
// DeleteAuthority 删除角色
func (s *AuthorityService) DeleteAuthority(ctx context.Context, authorityId uint) error {
if err := s.uc.DeleteAuthority(ctx, authorityId); err != nil {
return err
}
// 刷新Casbin
_ = s.casbin.FreshCasbin()
return nil
}
// GetAuthorityList 获取角色列表
func (s *AuthorityService) GetAuthorityList(ctx context.Context, authorityId uint) ([]*AuthorityFullInfo, error) {
list, err := s.uc.GetAuthorityInfoList(ctx, authorityId)
if err != nil {
return nil, err
}
return toAuthorityFullInfoList(list), nil
}
// SetDataAuthorityRequest 设置角色资源权限请求
type SetDataAuthorityRequest struct {
AuthorityId uint `json:"authorityId"`
DataAuthorityIds []uint `json:"dataAuthorityId"`
}
// SetDataAuthority 设置角色资源权限
func (s *AuthorityService) SetDataAuthority(ctx context.Context, adminAuthorityID uint, req *SetDataAuthorityRequest) error {
return s.uc.SetDataAuthority(ctx, adminAuthorityID, req.AuthorityId, req.DataAuthorityIds)
}
// 转换函数
func toAuthorityFullInfo(auth *system.Authority) *AuthorityFullInfo {
info := &AuthorityFullInfo{
AuthorityId: auth.AuthorityId,
AuthorityName: auth.AuthorityName,
ParentId: auth.ParentId,
DefaultRouter: auth.DefaultRouter,
}
return info
}
func toAuthorityFullInfoList(list []*system.AuthorityFull) []*AuthorityFullInfo {
result := make([]*AuthorityFullInfo, len(list))
for i, auth := range list {
result[i] = &AuthorityFullInfo{
AuthorityId: auth.AuthorityId,
AuthorityName: auth.AuthorityName,
ParentId: auth.ParentId,
DefaultRouter: auth.DefaultRouter,
Children: toAuthorityFullInfoList(auth.Children),
}
// DataAuthorityId
if len(auth.DataAuthorityId) > 0 {
result[i].DataAuthorityId = make([]*AuthorityInfo, len(auth.DataAuthorityId))
for j, da := range auth.DataAuthorityId {
result[i].DataAuthorityId[j] = &AuthorityInfo{
AuthorityId: da.AuthorityId,
AuthorityName: da.AuthorityName,
ParentId: da.ParentId,
DefaultRouter: da.DefaultRouter,
}
}
}
}
return result
}
// RegisterRoutes 注册路由
func (s *AuthorityService) RegisterRoutes(srv *http.Server) {
r := srv.Route("/")
r.POST("/authority/createAuthority", s.handleCreateAuthority)
r.POST("/authority/copyAuthority", s.handleCopyAuthority)
r.PUT("/authority/updateAuthority", s.handleUpdateAuthority)
r.POST("/authority/deleteAuthority", s.handleDeleteAuthority)
r.POST("/authority/getAuthorityList", s.handleGetAuthorityList)
r.POST("/authority/setDataAuthority", s.handleSetDataAuthority)
}
// HTTP Handlers
func (s *AuthorityService) handleCreateAuthority(ctx http.Context) error {
var req CreateAuthorityRequest
if err := ctx.Bind(&req); err != nil {
return err
}
resp, err := s.CreateAuthority(ctx, &req)
if err != nil {
return errors.BadRequest("CREATE_FAILED", err.Error())
}
return ctx.Result(200, map[string]any{"code": 0, "msg": "创建成功", "data": map[string]any{"authority": resp}})
}
func (s *AuthorityService) handleCopyAuthority(ctx http.Context) error {
var req CopyAuthorityRequest
if err := ctx.Bind(&req); err != nil {
return err
}
adminAuthorityID := middleware.GetAuthorityID(ctx)
resp, err := s.CopyAuthority(ctx, adminAuthorityID, &req)
if err != nil {
return errors.BadRequest("COPY_FAILED", err.Error())
}
return ctx.Result(200, map[string]any{"code": 0, "msg": "复制成功", "data": map[string]any{"authority": resp}})
}
func (s *AuthorityService) handleUpdateAuthority(ctx http.Context) error {
var req UpdateAuthorityRequest
if err := ctx.Bind(&req); err != nil {
return err
}
resp, err := s.UpdateAuthority(ctx, &req)
if err != nil {
return errors.BadRequest("UPDATE_FAILED", err.Error())
}
return ctx.Result(200, map[string]any{"code": 0, "msg": "更新成功", "data": map[string]any{"authority": resp}})
}
func (s *AuthorityService) handleDeleteAuthority(ctx http.Context) error {
var req struct {
AuthorityId uint `json:"authorityId"`
}
if err := ctx.Bind(&req); err != nil {
return err
}
if err := s.DeleteAuthority(ctx, req.AuthorityId); err != nil {
return errors.BadRequest("DELETE_FAILED", err.Error())
}
return ctx.Result(200, map[string]any{"code": 0, "msg": "删除成功"})
}
func (s *AuthorityService) handleGetAuthorityList(ctx http.Context) error {
authorityId := middleware.GetAuthorityID(ctx)
resp, err := s.GetAuthorityList(ctx, authorityId)
if err != nil {
return errors.InternalServer("LIST_ERROR", err.Error())
}
return ctx.Result(200, map[string]any{"code": 0, "msg": "获取成功", "data": map[string]any{"list": resp}})
}
func (s *AuthorityService) handleSetDataAuthority(ctx http.Context) error {
var req SetDataAuthorityRequest
if err := ctx.Bind(&req); err != nil {
return err
}
adminAuthorityID := middleware.GetAuthorityID(ctx)
if err := s.SetDataAuthority(ctx, adminAuthorityID, &req); err != nil {
return errors.BadRequest("SET_FAILED", err.Error())
}
return ctx.Result(200, map[string]any{"code": 0, "msg": "设置成功"})
}