438 lines
13 KiB
Go
438 lines
13 KiB
Go
package logic
|
||
|
||
import (
|
||
"fmt"
|
||
|
||
"github.com/eryajf-world/go-ldap-admin/model"
|
||
"github.com/eryajf-world/go-ldap-admin/public/common"
|
||
"github.com/eryajf-world/go-ldap-admin/public/tools"
|
||
"github.com/eryajf-world/go-ldap-admin/service/isql"
|
||
"github.com/eryajf-world/go-ldap-admin/svc/request"
|
||
"github.com/eryajf-world/go-ldap-admin/svc/response"
|
||
|
||
"github.com/gin-gonic/gin"
|
||
"github.com/thoas/go-funk"
|
||
)
|
||
|
||
type RoleLogic struct{}
|
||
|
||
// Add 添加数据
|
||
func (l RoleLogic) Add(c *gin.Context, req interface{}) (data interface{}, rspError interface{}) {
|
||
r, ok := req.(*request.RoleAddReq)
|
||
if !ok {
|
||
return nil, ReqAssertErr
|
||
}
|
||
_ = c
|
||
|
||
if isql.Role.Exist(tools.H{"name": r.Name}) {
|
||
return nil, tools.NewValidatorError(fmt.Errorf("该角色名已存在"))
|
||
}
|
||
|
||
// 获取当前用户最高角色等级
|
||
minSort, ctxUser, err := isql.User.GetCurrentUserMinRoleSort(c)
|
||
if err != nil {
|
||
return nil, tools.NewMySqlError(fmt.Errorf("获取当前用户最高角色等级失败: %s", err.Error()))
|
||
}
|
||
if minSort != 1 {
|
||
return nil, tools.NewValidatorError(fmt.Errorf("当前用户没有权限更新角色"))
|
||
}
|
||
// 用户不能创建比自己等级高或相同等级的角色
|
||
if minSort >= r.Sort {
|
||
return nil, tools.NewValidatorError(fmt.Errorf("不能创建比自己等级高或相同等级的角色"))
|
||
}
|
||
|
||
role := model.Role{
|
||
Name: r.Name,
|
||
Keyword: r.Keyword,
|
||
Remark: r.Remark,
|
||
Status: r.Status,
|
||
Sort: r.Sort,
|
||
Creator: ctxUser.Username,
|
||
}
|
||
|
||
// 创建角色
|
||
err = isql.Role.Add(&role)
|
||
if err != nil {
|
||
return nil, tools.NewMySqlError(fmt.Errorf("创建角色失败: %s", err.Error()))
|
||
}
|
||
return nil, nil
|
||
}
|
||
|
||
// List 数据列表
|
||
func (l RoleLogic) List(c *gin.Context, req interface{}) (data interface{}, rspError interface{}) {
|
||
r, ok := req.(*request.RoleListReq)
|
||
if !ok {
|
||
return nil, ReqAssertErr
|
||
}
|
||
_ = c
|
||
|
||
// 获取数据列表
|
||
roles, err := isql.Role.List(r)
|
||
if err != nil {
|
||
return nil, tools.NewMySqlError(fmt.Errorf("获取菜单列表失败: %s", err.Error()))
|
||
}
|
||
|
||
count, err := isql.Role.Count()
|
||
if err != nil {
|
||
return nil, tools.NewMySqlError(fmt.Errorf("获取接口总数失败"))
|
||
}
|
||
|
||
rets := make([]model.Role, 0)
|
||
for _, role := range roles {
|
||
rets = append(rets, *role)
|
||
}
|
||
|
||
return response.RoleListRsp{
|
||
Total: count,
|
||
Roles: rets,
|
||
}, nil
|
||
}
|
||
|
||
// Update 更新数据
|
||
func (l RoleLogic) Update(c *gin.Context, req interface{}) (data interface{}, rspError interface{}) {
|
||
r, ok := req.(*request.RoleUpdateReq)
|
||
if !ok {
|
||
return nil, ReqAssertErr
|
||
}
|
||
_ = c
|
||
|
||
filter := tools.H{"id": r.ID}
|
||
if !isql.Role.Exist(filter) {
|
||
return nil, tools.NewValidatorError(fmt.Errorf("该角色名不已存在"))
|
||
}
|
||
|
||
// 当前用户角色排序最小值(最高等级角色)以及当前用户
|
||
minSort, ctxUser, err := isql.User.GetCurrentUserMinRoleSort(c)
|
||
if err != nil {
|
||
return nil, tools.NewMySqlError(fmt.Errorf("获取当前用户最高角色等级失败: %s", err.Error()))
|
||
}
|
||
|
||
if minSort != 1 {
|
||
return nil, tools.NewValidatorError(fmt.Errorf("当前用户没有权限更新角色"))
|
||
}
|
||
|
||
// 不能更新比自己角色等级高或相等的角色
|
||
// 根据path中的角色ID获取该角色信息
|
||
roles, err := isql.Role.GetRolesByIds([]uint{r.ID})
|
||
if err != nil || len(roles) == 0 {
|
||
return nil, tools.NewMySqlError(fmt.Errorf("获取角色信息失败: %s", err.Error()))
|
||
}
|
||
|
||
if minSort >= roles[0].Sort {
|
||
return nil, tools.NewValidatorError(fmt.Errorf("不能更新比自己角色等级高或相等的角色"))
|
||
}
|
||
|
||
// 不能把角色等级更新得比当前用户的等级高
|
||
if minSort >= r.Sort {
|
||
return nil, tools.NewValidatorError(fmt.Errorf("不能把角色等级更新得比当前用户的等级高或相同"))
|
||
}
|
||
oldData := new(model.Role)
|
||
err = isql.Role.Find(filter, oldData)
|
||
if err != nil {
|
||
return nil, tools.NewMySqlError(err)
|
||
}
|
||
role := model.Role{
|
||
Model: oldData.Model,
|
||
Name: r.Name,
|
||
Keyword: r.Keyword,
|
||
Remark: r.Remark,
|
||
Status: r.Status,
|
||
Sort: r.Sort,
|
||
Creator: ctxUser.Username,
|
||
}
|
||
|
||
// 更新角色
|
||
err = isql.Role.Update(&role)
|
||
if err != nil {
|
||
return nil, tools.NewMySqlError(fmt.Errorf("更新角色失败: %s", err.Error()))
|
||
}
|
||
|
||
// 如果更新成功,且更新了角色的keyword, 则更新casbin中policy
|
||
if r.Keyword != roles[0].Keyword {
|
||
// 获取policy
|
||
rolePolicies := common.CasbinEnforcer.GetFilteredPolicy(0, roles[0].Keyword)
|
||
if len(rolePolicies) == 0 {
|
||
return
|
||
}
|
||
rolePoliciesCopy := make([][]string, 0)
|
||
// 替换keyword
|
||
for _, policy := range rolePolicies {
|
||
policyCopy := make([]string, len(policy))
|
||
copy(policyCopy, policy)
|
||
rolePoliciesCopy = append(rolePoliciesCopy, policyCopy)
|
||
policy[0] = r.Keyword
|
||
}
|
||
|
||
//gormadapter未实现UpdatePolicies方法,等gorm更新---
|
||
//isUpdated, _ := common.CasbinEnforcer.UpdatePolicies(rolePoliciesCopy, rolePolicies)
|
||
//if !isUpdated {
|
||
// response.Fail(c, nil, "更新角色成功,但角色关键字关联的权限接口更新失败!")
|
||
// return
|
||
//}
|
||
|
||
// 这里需要先新增再删除(先删除再增加会出错)
|
||
isAdded, _ := common.CasbinEnforcer.AddPolicies(rolePolicies)
|
||
if !isAdded {
|
||
return nil, tools.NewOperationError(fmt.Errorf("更新角色成功,但角色关键字关联的权限接口更新失败"))
|
||
}
|
||
isRemoved, _ := common.CasbinEnforcer.RemovePolicies(rolePoliciesCopy)
|
||
if !isRemoved {
|
||
return nil, tools.NewOperationError(fmt.Errorf("更新角色成功,但角色关键字关联的权限接口更新失败"))
|
||
}
|
||
err := common.CasbinEnforcer.LoadPolicy()
|
||
if err != nil {
|
||
return nil, tools.NewOperationError(fmt.Errorf("更新角色成功,但角色关键字关联角色的权限接口策略加载失败"))
|
||
}
|
||
|
||
}
|
||
|
||
// 更新角色成功处理用户信息缓存有两种做法:(这里使用第二种方法,因为一个角色下用户数量可能很多,第二种方法可以分散数据库压力)
|
||
// 1.可以帮助用户更新拥有该角色的用户信息缓存,使用下面方法
|
||
// err = ur.UpdateUserInfoCacheByRoleId(uint(roleId))
|
||
// 2.直接清理缓存,让活跃的用户自己重新缓存最新用户信息
|
||
isql.User.ClearUserInfoCache()
|
||
|
||
return nil, nil
|
||
}
|
||
|
||
// Delete 删除数据
|
||
func (l RoleLogic) Delete(c *gin.Context, req interface{}) (data interface{}, rspError interface{}) {
|
||
r, ok := req.(*request.RoleDeleteReq)
|
||
if !ok {
|
||
return nil, ReqAssertErr
|
||
}
|
||
_ = c
|
||
|
||
// 获取当前登陆用户最高等级角色
|
||
minSort, _, err := isql.User.GetCurrentUserMinRoleSort(c)
|
||
if err != nil {
|
||
return nil, tools.NewMySqlError(fmt.Errorf("获取当前用户最高角色等级失败: %s", err.Error()))
|
||
}
|
||
|
||
// 获取角色信息
|
||
roles, err := isql.Role.GetRolesByIds(r.RoleIds)
|
||
if err != nil || len(roles) == 0 {
|
||
return nil, tools.NewMySqlError(fmt.Errorf("获取角色信息失败: %s", err.Error()))
|
||
}
|
||
|
||
// 不能删除比自己角色等级高或相等的角色
|
||
for _, role := range roles {
|
||
if minSort >= role.Sort {
|
||
return nil, tools.NewValidatorError(fmt.Errorf("不能删除比自己角色等级高或相等的角色"))
|
||
}
|
||
}
|
||
|
||
// 删除角色
|
||
err = isql.Role.Delete(r.RoleIds)
|
||
if err != nil {
|
||
return nil, tools.NewMySqlError(fmt.Errorf("删除角色失败: %s", err.Error()))
|
||
}
|
||
|
||
// 删除角色成功直接清理缓存,让活跃的用户自己重新缓存最新用户信息
|
||
isql.User.ClearUserInfoCache()
|
||
return nil, nil
|
||
}
|
||
|
||
// GetMenuList 获取角色菜单列表
|
||
func (l RoleLogic) GetMenuList(c *gin.Context, req interface{}) (data interface{}, rspError interface{}) {
|
||
r, ok := req.(*request.RoleGetMenuListReq)
|
||
if !ok {
|
||
return nil, ReqAssertErr
|
||
}
|
||
_ = c
|
||
|
||
menus, err := isql.Role.GetRoleMenusById(r.RoleID)
|
||
if err != nil {
|
||
return nil, tools.NewMySqlError(fmt.Errorf("获取角色的权限菜单失败: " + err.Error()))
|
||
}
|
||
return menus, nil
|
||
}
|
||
|
||
// GetApiList 获取角色接口列表
|
||
func (l RoleLogic) GetApiList(c *gin.Context, req interface{}) (data interface{}, rspError interface{}) {
|
||
r, ok := req.(*request.RoleGetApiListReq)
|
||
if !ok {
|
||
return nil, ReqAssertErr
|
||
}
|
||
_ = c
|
||
|
||
role := new(model.Role)
|
||
err := isql.Role.Find(tools.H{"id": r.RoleID}, role)
|
||
if err != nil {
|
||
return nil, tools.NewMySqlError(fmt.Errorf("获取资源失败: " + err.Error()))
|
||
}
|
||
|
||
policies := common.CasbinEnforcer.GetFilteredPolicy(0, role.Keyword)
|
||
|
||
apis, err := isql.Api.ListAll()
|
||
if err != nil {
|
||
return nil, tools.NewMySqlError(fmt.Errorf("获取资源列表失败: " + err.Error()))
|
||
}
|
||
accessApis := make([]*model.Api, 0)
|
||
|
||
for _, policy := range policies {
|
||
path := policy[1]
|
||
method := policy[2]
|
||
for _, api := range apis {
|
||
if path == api.Path && method == api.Method {
|
||
accessApis = append(accessApis, api)
|
||
break
|
||
}
|
||
}
|
||
}
|
||
|
||
return accessApis, nil
|
||
}
|
||
|
||
// UpdateMenus 更新角色菜单
|
||
func (l RoleLogic) UpdateMenus(c *gin.Context, req interface{}) (data interface{}, rspError interface{}) {
|
||
r, ok := req.(*request.RoleUpdateMenusReq)
|
||
if !ok {
|
||
return nil, ReqAssertErr
|
||
}
|
||
_ = c
|
||
|
||
roles, err := isql.Role.GetRolesByIds([]uint{r.RoleID})
|
||
if err != nil || len(roles) == 0 {
|
||
return nil, tools.NewMySqlError(fmt.Errorf("未获取到角色信息"))
|
||
}
|
||
|
||
// 当前用户角色排序最小值(最高等级角色)以及当前用户
|
||
minSort, ctxUser, err := isql.User.GetCurrentUserMinRoleSort(c)
|
||
if err != nil {
|
||
return nil, tools.NewMySqlError(fmt.Errorf("获取当前用户最高角色等级失败: %s", err.Error()))
|
||
}
|
||
|
||
// (非管理员)不能更新比自己角色等级高或相等角色的权限菜单
|
||
if minSort != 1 {
|
||
if minSort >= roles[0].Sort {
|
||
return nil, tools.NewValidatorError(fmt.Errorf("不能更新比自己角色等级高或相等角色的权限菜单"))
|
||
}
|
||
}
|
||
|
||
// 获取当前用户所拥有的权限菜单
|
||
ctxUserMenus, err := isql.Menu.GetUserMenusByUserId(ctxUser.ID)
|
||
if err != nil {
|
||
return nil, tools.NewMySqlError(fmt.Errorf("获取当前用户的可访问菜单列表失败: " + err.Error()))
|
||
}
|
||
|
||
// 获取当前用户所拥有的权限菜单ID
|
||
ctxUserMenusIds := make([]uint, 0)
|
||
for _, menu := range ctxUserMenus {
|
||
ctxUserMenusIds = append(ctxUserMenusIds, menu.ID)
|
||
}
|
||
|
||
// 用户需要修改的菜单集合
|
||
reqMenus := make([]*model.Menu, 0)
|
||
|
||
// (非管理员)不能把角色的权限菜单设置的比当前用户所拥有的权限菜单多
|
||
if minSort != 1 {
|
||
for _, id := range r.MenuIds {
|
||
if !funk.Contains(ctxUserMenusIds, id) {
|
||
return nil, tools.NewValidatorError(fmt.Errorf("无权设置ID为%d的菜单", id))
|
||
}
|
||
}
|
||
|
||
for _, id := range r.MenuIds {
|
||
for _, menu := range ctxUserMenus {
|
||
if id == menu.ID {
|
||
reqMenus = append(reqMenus, menu)
|
||
break
|
||
}
|
||
}
|
||
}
|
||
} else {
|
||
// 管理员随意设置
|
||
// 根据menuIds查询查询菜单
|
||
menus, err := isql.Menu.List()
|
||
if err != nil {
|
||
return nil, tools.NewValidatorError(fmt.Errorf("获取菜单列表失败: " + err.Error()))
|
||
}
|
||
for _, menuId := range r.MenuIds {
|
||
for _, menu := range menus {
|
||
if menuId == menu.ID {
|
||
reqMenus = append(reqMenus, menu)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
roles[0].Menus = reqMenus
|
||
|
||
err = isql.Role.UpdateRoleMenus(roles[0])
|
||
if err != nil {
|
||
return nil, tools.NewMySqlError(fmt.Errorf("更新角色的权限菜单失败: " + err.Error()))
|
||
}
|
||
|
||
return nil, nil
|
||
}
|
||
|
||
// UpdateApis 更新角色接口
|
||
func (l RoleLogic) UpdateApis(c *gin.Context, req interface{}) (data interface{}, rspError interface{}) {
|
||
r, ok := req.(*request.RoleUpdateApisReq)
|
||
if !ok {
|
||
return nil, ReqAssertErr
|
||
}
|
||
_ = c
|
||
|
||
// 根据path中的角色ID获取该角色信息
|
||
roles, err := isql.Role.GetRolesByIds([]uint{r.RoleID})
|
||
if err != nil || len(roles) == 0 {
|
||
return nil, tools.NewMySqlError(fmt.Errorf("未获取到角色信息"))
|
||
}
|
||
|
||
// 当前用户角色排序最小值(最高等级角色)以及当前用户
|
||
minSort, ctxUser, err := isql.User.GetCurrentUserMinRoleSort(c)
|
||
if err != nil {
|
||
return nil, tools.NewMySqlError(fmt.Errorf("获取当前用户最高角色等级失败: %s", err.Error()))
|
||
}
|
||
|
||
// (非管理员)不能更新比自己角色等级高或相等角色的权限菜单
|
||
if minSort != 1 {
|
||
if minSort >= roles[0].Sort {
|
||
return nil, tools.NewValidatorError(fmt.Errorf("不能更新比自己角色等级高或相等角色的权限菜单"))
|
||
}
|
||
}
|
||
|
||
// 获取当前用户所拥有的权限接口
|
||
ctxRoles := ctxUser.Roles
|
||
ctxRolesPolicies := make([][]string, 0)
|
||
for _, role := range ctxRoles {
|
||
policy := common.CasbinEnforcer.GetFilteredPolicy(0, role.Keyword)
|
||
ctxRolesPolicies = append(ctxRolesPolicies, policy...)
|
||
}
|
||
// 得到path中的角色ID对应角色能够设置的权限接口集合
|
||
for _, policy := range ctxRolesPolicies {
|
||
policy[0] = roles[0].Keyword
|
||
}
|
||
|
||
// 根据apiID获取接口详情
|
||
apis, err := isql.Api.GetApisById(r.ApiIds)
|
||
if err != nil {
|
||
return nil, tools.NewMySqlError(fmt.Errorf("根据接口ID获取接口信息失败"))
|
||
}
|
||
// 生成前端想要设置的角色policies
|
||
reqRolePolicies := make([][]string, 0)
|
||
for _, api := range apis {
|
||
reqRolePolicies = append(reqRolePolicies, []string{
|
||
roles[0].Keyword, api.Path, api.Method,
|
||
})
|
||
}
|
||
|
||
// (非管理员)不能把角色的权限接口设置的比当前用户所拥有的权限接口多
|
||
if minSort != 1 {
|
||
for _, reqPolicy := range reqRolePolicies {
|
||
if !funk.Contains(ctxRolesPolicies, reqPolicy) {
|
||
return nil, tools.NewValidatorError(fmt.Errorf("无权设置路径为%s,请求方式为%s的接口", reqPolicy[1], reqPolicy[2]))
|
||
}
|
||
}
|
||
}
|
||
|
||
// 更新角色的权限接口
|
||
err = isql.Role.UpdateRoleApis(roles[0].Keyword, reqRolePolicies)
|
||
if err != nil {
|
||
return nil, tools.NewMySqlError(fmt.Errorf("更新角色的权限接口失败"))
|
||
}
|
||
return nil, nil
|
||
}
|