416 lines
13 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* @desc:角色管理
* @company:云南奇讯科技有限公司
* @Author: yixiaohu<yxh669@qq.com>
* @Date: 2022/9/26 15:54
*/
package sysRole
import (
"context"
"errors"
"github.com/gogf/gf/v2/container/garray"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv"
"github.com/tiger1103/gfast/v3/api/v1/system"
commonService "github.com/tiger1103/gfast/v3/internal/app/common/service"
"github.com/tiger1103/gfast/v3/internal/app/system/consts"
"github.com/tiger1103/gfast/v3/internal/app/system/dao"
"github.com/tiger1103/gfast/v3/internal/app/system/model"
"github.com/tiger1103/gfast/v3/internal/app/system/model/do"
"github.com/tiger1103/gfast/v3/internal/app/system/model/entity"
"github.com/tiger1103/gfast/v3/internal/app/system/service"
"github.com/tiger1103/gfast/v3/library/libWebsocket"
"github.com/tiger1103/gfast/v3/library/liberr"
)
func init() {
service.RegisterSysRole(New())
}
func New() service.ISysRole {
return &sSysRole{}
}
type sSysRole struct {
}
func (s *sSysRole) GetRoleListSearch(ctx context.Context, req *system.RoleListReq) (res *system.RoleListRes, err error) {
res = new(system.RoleListRes)
err = g.Try(ctx, func(ctx context.Context) {
model := dao.SysRole.Ctx(ctx)
if req.RoleName != "" {
model = model.Where("a.name like ?", "%"+req.RoleName+"%")
}
if req.Status != "" {
model = model.Where("a.status", gconv.Int(req.Status))
}
userId := service.Context().GetUserId(ctx)
//获取当前用户所属角色ids
if !service.SysUser().IsSupperAdmin(ctx, userId) {
var roleIds []uint
roleIds, err = service.SysUser().GetAdminRoleIds(ctx, userId, true)
liberr.ErrIsNil(ctx, err)
if len(roleIds) == 0 {
return
}
model = model.Where("a."+dao.SysRole.Columns().Id+" in(?) OR a.created_by = ?", roleIds, userId)
}
model = model.As("a")
if service.ToolsGenTable().IsMysql() {
model = model.LeftJoin("casbin_rule", "b", "b.v1 = a.id ")
model = model.LeftJoin("sys_user", "u", "CONCAT('u_',u.id) = b.v0 ")
} else {
model = model.LeftJoin("casbin_rule", "b", "b.v1 = cast(a.id AS VARCHAR) ")
model = model.LeftJoin("sys_user", "u", "CONCAT('u_',u.id) = b.v0")
}
model = model.Group("a.id")
err = model.Order("id asc").Fields("a.*, count(u.id) user_cnt").Scan(&res.List)
liberr.ErrIsNil(ctx, err, "获取数据失败")
})
return
}
// GetRoleList 获取角色列表
func (s *sSysRole) GetRoleList(ctx context.Context) (list []*entity.SysRole, err error) {
cache := commonService.Cache()
//从缓存获取
iList := cache.GetOrSetFuncLock(ctx, consts.CacheSysRole, s.getRoleListFromDb, 0, consts.CacheSysAuthTag)
if !iList.IsEmpty() {
err = gconv.Struct(iList, &list)
}
return
}
// 从数据库获取所有角色
func (s *sSysRole) getRoleListFromDb(ctx context.Context) (value interface{}, err error) {
err = g.Try(ctx, func(ctx context.Context) {
var v []*entity.SysRole
//从数据库获取
err = dao.SysRole.Ctx(ctx).
Order(dao.SysRole.Columns().ListOrder + " asc," + dao.SysRole.Columns().Id + " asc").
Scan(&v)
liberr.ErrIsNil(ctx, err, "获取角色数据失败")
value = v
})
return
}
// AddRoleRule 添加角色权限
func (s *sSysRole) AddRoleRule(ctx context.Context, ruleIds []uint, roleId int64) (err error) {
err = g.Try(ctx, func(ctx context.Context) {
enforcer, e := commonService.CasbinEnforcer(ctx)
liberr.ErrIsNil(ctx, e)
ruleIdsStr := gconv.Strings(ruleIds)
rules := make([][]string, len(ruleIdsStr))
for k, v := range ruleIdsStr {
rules[k] = []string{gconv.String(roleId), v, "All"}
}
if len(rules) > 0 {
_, err = enforcer.AddPolicies(rules)
liberr.ErrIsNil(ctx, err)
}
})
return
}
// DelRoleRule 删除角色权限
func (s *sSysRole) DelRoleRule(ctx context.Context, roleId int64) (err error) {
err = g.Try(ctx, func(ctx context.Context) {
enforcer, e := commonService.CasbinEnforcer(ctx)
liberr.ErrIsNil(ctx, e)
_, err = enforcer.RemoveFilteredPolicy(0, gconv.String(roleId))
liberr.ErrIsNil(ctx, e)
})
return
}
func (s *sSysRole) AddRole(ctx context.Context, req *system.RoleAddReq) (err error) {
err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
err = g.Try(ctx, func(ctx context.Context) {
req.CreatedBy = service.Context().GetUserId(ctx)
roleId, e := dao.SysRole.Ctx(ctx).TX(tx).InsertAndGetId(do.SysRole{
Pid: req.Pid,
Status: req.Status,
ListOrder: req.ListOrder,
Name: req.Name,
Remark: req.Remark,
CreatedBy: req.CreatedBy,
EffectiveTime: req.EffectiveTimeInfo,
})
liberr.ErrIsNil(ctx, e, "添加角色失败")
//过滤ruleIds 把没有权限的过滤掉
req.MenuIds, err = s.filterAccessRuleIds(ctx, req.MenuIds)
liberr.ErrIsNil(ctx, err)
//添加角色权限
e = s.AddRoleRule(ctx, req.MenuIds, roleId)
liberr.ErrIsNil(ctx, e)
//清除缓存
commonService.Cache().Remove(ctx, consts.CacheSysRole)
})
return err
})
return
}
func (s *sSysRole) Get(ctx context.Context, id uint) (res *model.RoleInfoRes, err error) {
err = g.Try(ctx, func(ctx context.Context) {
//判断是否具有此角色的权限
if !s.hasManageAccess(ctx, id, true) {
liberr.ErrIsNil(ctx, errors.New("没有查看这个角色的权限"))
}
res = new(model.RoleInfoRes)
err = dao.SysRole.Ctx(ctx).WherePri(id).Scan(&res.SysRole)
liberr.ErrIsNil(ctx, err, "获取角色信息失败")
err = gconv.Struct(res.SysRole.EffectiveTime, &res.EffectiveTimeInfo)
if err != nil {
res.EffectiveTimeInfo = new(model.EffectiveTimeInfo)
}
})
return
}
// GetFilteredNamedPolicy 获取角色关联的菜单规则
func (s *sSysRole) GetFilteredNamedPolicy(ctx context.Context, id uint) (gpSlice []int, err error) {
err = g.Try(ctx, func(ctx context.Context) {
enforcer, e := commonService.CasbinEnforcer(ctx)
liberr.ErrIsNil(ctx, e)
gp := enforcer.GetFilteredNamedPolicy("p", 0, gconv.String(id))
gpSlice = make([]int, len(gp))
for k, v := range gp {
gpSlice[k] = gconv.Int(v[1])
}
})
return
}
func (s *sSysRole) hasManageAccess(ctx context.Context, roleId uint, includeChildren ...bool) bool {
currentUserId := service.Context().GetUserId(ctx)
if !service.SysUser().IsSupperAdmin(ctx, currentUserId) {
var (
roleIds []uint
hasAccess bool
err error
list []*entity.SysRole
)
list, err = s.GetRoleList(ctx)
if err != nil {
g.Log().Error(ctx, err)
return false
}
for _, v := range list {
//判断是否当前用户所建角色
if roleId == v.Id && v.CreatedBy == currentUserId {
return true
}
}
roleIds, err = service.SysUser().GetAdminRoleIds(ctx, service.Context().GetUserId(ctx), includeChildren...)
if err != nil {
g.Log().Error(ctx, err)
return false
}
if len(roleIds) > 0 {
for _, v := range roleIds {
if v == roleId {
hasAccess = true
break
}
}
}
return hasAccess
}
return true
}
// EditRole 修改角色
func (s *sSysRole) EditRole(ctx context.Context, req *system.RoleEditReq) (err error) {
err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
err = g.Try(ctx, func(ctx context.Context) {
//判断是否具有修改此角色的权限
if !s.hasManageAccess(ctx, gconv.Uint(req.Id), true) {
liberr.ErrIsNil(ctx, errors.New("没有修改这个角色的权限"))
}
_, e := dao.SysRole.Ctx(ctx).TX(tx).WherePri(req.Id).Data(&do.SysRole{
Pid: req.Pid,
Status: req.Status,
ListOrder: req.ListOrder,
Name: req.Name,
Remark: req.Remark,
EffectiveTime: req.EffectiveTimeInfo,
}).Update()
liberr.ErrIsNil(ctx, e, "修改角色失败")
//过滤ruleIds 把没有权限的过滤掉
req.MenuIds, err = s.filterAccessRuleIds(ctx, req.MenuIds)
liberr.ErrIsNil(ctx, err)
//删除角色权限
e = s.DelRoleRule(ctx, req.Id)
liberr.ErrIsNil(ctx, e)
//添加角色权限
e = s.AddRoleRule(ctx, req.MenuIds, req.Id)
liberr.ErrIsNil(ctx, e)
//清除缓存
commonService.Cache().Remove(ctx, consts.CacheSysRole)
//通知刷新token
s.refreshToken(ctx, req.Id)
})
return err
})
return
}
// 从给定的menuIds中过滤掉用户没有操作权限的菜单id
func (s *sSysRole) filterAccessRuleIds(ctx context.Context, menuIds []uint) (newRuleIds []uint, err error) {
err = g.Try(ctx, func(ctx context.Context) {
//若不是超管过滤ruleIds 把没有权限的过滤掉
if !service.SysUser().IsSupperAdmin(ctx, service.Context().GetUserId(ctx)) {
var (
userRoleIds []uint
accessMenus *garray.Array
)
userRoleIds, err = service.SysUser().GetAdminRoleIds(ctx, service.Context().GetUserId(ctx))
liberr.ErrIsNil(ctx, err)
accessMenus, err = service.SysUser().GetAdminMenusIdsByRoleIds(ctx, userRoleIds)
for _, v := range menuIds {
if accessMenus.Contains(v) {
newRuleIds = append(newRuleIds, v)
}
}
} else {
newRuleIds = menuIds
}
})
return
}
// DeleteByIds 删除角色
func (s *sSysRole) DeleteByIds(ctx context.Context, ids []int64) (err error) {
err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
err = g.Try(ctx, func(ctx context.Context) {
for _, id := range ids {
//判断是否有删除该角色的权限
if !s.hasManageAccess(ctx, gconv.Uint(id)) {
liberr.ErrIsNil(ctx, errors.New("没有删除这个角色的权限"))
}
}
_, err = dao.SysRole.Ctx(ctx).TX(tx).Where(dao.SysRole.Columns().Id+" in(?)", ids).Delete()
liberr.ErrIsNil(ctx, err, "删除角色失败")
//删除角色权限
for _, v := range ids {
err = s.DelRoleRule(ctx, v)
liberr.ErrIsNil(ctx, err)
}
//清除缓存
commonService.Cache().Remove(ctx, consts.CacheSysRole)
})
return err
})
return
}
func (s *sSysRole) RoleDeptTreeSelect(ctx context.Context) (res *system.RoleDeptTreeSelectRes, err error) {
res = new(system.RoleDeptTreeSelectRes)
err = g.Try(ctx, func(ctx context.Context) {
list, err := service.SysDept().GetList(ctx, &system.DeptSearchReq{
Status: "1",
ShowAll: true,
})
liberr.ErrIsNil(ctx, err)
dList := service.SysDept().GetListTree(0, list)
res.Depts = dList
})
return
}
func (s *sSysRole) GetRoleDataScope(ctx context.Context, roleId uint) (data []*model.ScopeAuthData, err error) {
err = g.Try(ctx, func(ctx context.Context) {
err = dao.SysRoleScope.Ctx(ctx).Where("role_id", roleId).Scan(&data)
liberr.ErrIsNil(ctx, err, "获取角色数据权限失败")
})
return
}
func (s *sSysRole) GetRoleMenuScope(ctx context.Context, roleIds []uint, menuId uint) (data []*model.ScopeAuthData, err error) {
err = g.Try(ctx, func(ctx context.Context) {
err = dao.SysRoleScope.Ctx(ctx).WhereIn("role_id", roleIds).
Where("menu_id", menuId).
Scan(&data)
liberr.ErrIsNil(ctx, err, "获取角色数据权限失败")
})
return
}
// RoleDataScope 设置角色数据权限
func (s *sSysRole) RoleDataScope(ctx context.Context, req *system.DataScopeReq) error {
err := g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
err := g.Try(ctx, func(ctx context.Context) {
data := make([]do.SysRoleScope, 0, len(req.AuthData))
for _, v := range req.AuthData {
if v.MenuId != 0 && v.Scope != 0 {
data = append(data, do.SysRoleScope{
RoleId: req.RoleId,
MenuId: v.MenuId,
DataScope: v.Scope,
DeptIds: gconv.String(v.DeptIds),
})
}
}
//清除旧权限
_, err := dao.SysRoleScope.Ctx(ctx).Where(dao.SysRoleScope.Columns().RoleId, req.RoleId).
Delete()
liberr.ErrIsNil(ctx, err, "清除旧权限信息失败")
if len(data) > 0 {
_, err = dao.SysRoleScope.Ctx(ctx).Data(data).Insert()
liberr.ErrIsNil(ctx, err, "设置权限信息失败")
}
//通知刷新token
s.refreshToken(ctx, gconv.Int64(req.RoleId))
})
return err
})
return err
}
func (s *sSysRole) FindSonByParentId(roleList []*entity.SysRole, id uint) []*entity.SysRole {
children := make([]*entity.SysRole, 0, len(roleList))
for _, v := range roleList {
if v.Pid == id {
children = append(children, v)
fChildren := s.FindSonByParentId(roleList, v.Id)
children = append(children, fChildren...)
}
}
return children
}
func (s *sSysRole) FindSonIdsByParentId(roleList []*entity.SysRole, id uint) []uint {
children := make([]uint, 0, len(roleList))
for _, v := range roleList {
if v.Pid == id {
children = append(children, v.Id)
fChildren := s.FindSonIdsByParentId(roleList, v.Id)
children = append(children, fChildren...)
}
}
return children
}
// 刷新角色下用户token
func (s *sSysRole) refreshToken(ctx context.Context, roleId int64) {
_ = g.Try(ctx, func(ctx context.Context) {
enforcer, e := commonService.CasbinEnforcer(ctx)
liberr.ErrIsNil(ctx, e)
userRoleIds := enforcer.GetFilteredGroupingPolicy(1, gconv.String(roleId))
for _, v := range userRoleIds {
userId := gstr.Split(v[0], "_")[1]
//通知用户更新token
libWebsocket.SendToUser(gconv.Uint64(userId), &libWebsocket.WResponse{
Event: consts.WebsocketTypeTokenUpdated,
Data: nil,
})
}
})
}