任务三
This commit is contained in:
parent
7df0450b1e
commit
03252d34e1
|
|
@ -50,6 +50,9 @@ type CasbinRepo interface {
|
|||
UpdateCasbinApi(oldPath, newPath, oldMethod, newMethod string) error
|
||||
GetPolicyPathByAuthorityId(authorityId uint) []CasbinRule
|
||||
FreshCasbin() error
|
||||
AddPolicies(rules [][]string) error
|
||||
UpdateCasbin(adminAuthorityID, authorityId uint, casbinInfos []CasbinRule) error
|
||||
RemoveFilteredPolicy(authorityId string) error
|
||||
}
|
||||
|
||||
// ApiUsecase API用例
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
@ -67,11 +67,13 @@ type MenuRepo interface {
|
|||
UpdateBaseMenu(ctx context.Context, menu *BaseMenu) error
|
||||
DeleteBaseMenu(ctx context.Context, id uint) error
|
||||
FindBaseMenuByID(ctx context.Context, id uint) (*BaseMenu, error)
|
||||
FindBaseMenuByName(ctx context.Context, name string) (*BaseMenu, error)
|
||||
FindAllBaseMenus(ctx context.Context) ([]*BaseMenu, error)
|
||||
FindBaseMenusByIds(ctx context.Context, ids []string) ([]*BaseMenu, error)
|
||||
FindAuthorityMenuIds(ctx context.Context, authorityId uint) ([]string, error)
|
||||
FindAuthorityBtns(ctx context.Context, authorityId uint) ([]*AuthorityBtn, error)
|
||||
SetMenuAuthority(ctx context.Context, authorityId uint, menuIds []uint) error
|
||||
CheckMenuInAuthority(ctx context.Context, authorityId uint, menuName string) (bool, error)
|
||||
}
|
||||
|
||||
// MenuUsecase 菜单用例
|
||||
|
|
@ -291,3 +293,18 @@ func (uc *MenuUsecase) GetMenuAuthority(ctx context.Context, authorityId uint) (
|
|||
}
|
||||
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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -249,6 +249,40 @@ func (r *menuRepo) FindBaseMenuByID(ctx context.Context, id uint) (*system.BaseM
|
|||
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 获取所有基础菜单
|
||||
func (r *menuRepo) FindAllBaseMenus(ctx context.Context) ([]*system.BaseMenu, error) {
|
||||
var menus []model.SysBaseMenu
|
||||
|
|
|
|||
|
|
@ -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": "设置成功"})
|
||||
}
|
||||
Loading…
Reference in New Issue