在实际开发中,需要设置用户只能查看哪些部门的数据,这种情况一般称为数据权限。
例如对于销售,财务的数据,它们是非常敏感的,因此要求对数据权限进行控制, 对于基于集团性的应用系统而言,就更多需要控制好各自公司的数据了。如设置只能看本公司、或者本部门的数据,对于特殊的领导,可能需要跨部门的数据, 因此程序不能硬编码那个领导该访问哪些数据,需要进行后台的权限和数据权限的控制。

(捐赠版、授权版才有此功能)

数据权限演示

1、创建一个用于测试数据权限的表

CREATE TABLE `demo_data_auth` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `title` varchar(255) DEFAULT '' COMMENT '标题',
  `created_by` bigint(10) unsigned DEFAULT '0' COMMENT '创建人',
  `updated_by` bigint(10) unsigned DEFAULT '0' COMMENT '修改人',
  `created_at` datetime DEFAULT NULL COMMENT '创建时间',
  `updated_at` datetime DEFAULT NULL COMMENT '修改时间',
  `deleted_at` datetime DEFAULT NULL COMMENT '删除时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='数据权限测试';

2、使用代码生成相关逻辑

代码生成请参考:代码生成章节

代码生成->导入上面创建的表后设置一下生成信息:

生成后使用不同用户创建相关数据,此时还没接入数据权限验证,我们稍后接入:

3、添加数据权限判断功能

添加数据权限需要和用户表关联查询

注意数据权限和用户相关,所以业务表里面必须带有created_by字段,否则权限不生效。

列表页查询权限控制,修改internal/app/demo/logic/demoDataAuth/demo_data_auth.go文件List方法内容:

#修改列表页面
func (s *sDemoDataAuth) List(ctx context.Context, req *model.DemoDataAuthSearchReq) (listRes *model.DemoDataAuthSearchRes, err error) {
    listRes = new(model.DemoDataAuthSearchRes)
    err = g.Try(ctx, func(ctx context.Context) {
        m := dao.DemoDataAuth.Ctx(ctx).WithAll().As("demo").
            LeftJoin("sys_user user", "demo.created_by=user.id")
        if req.Id != "" {
            m = m.Where("demo."+dao.DemoDataAuth.Columns().Id+" = ?", req.Id)
        }
        if req.Title != "" {
            m = m.Where("demo."+dao.DemoDataAuth.Columns().Title+" = ?", req.Title)
        }
        if req.CreatedBy != "" {
            m = m.Where("demo."+dao.DemoDataAuth.Columns().CreatedBy+" = ?", gconv.Uint(req.CreatedBy))
        }
        if len(req.DateRange) != 0 {
            m = m.Where("demo."+dao.DemoDataAuth.Columns().CreatedAt+" >=? AND demo."+dao.DemoDataAuth.Columns().CreatedAt+" <=?", req.DateRange[0], req.DateRange[1])
        }
        //添加数据权限判断条件
        var (
            where  g.Map
            ent    *entity.DemoDataAuth
            //获取当前请求api接口对应的菜单
            url    = gstr.TrimLeft(ghttp.RequestFromCtx(ctx).Request.URL.Path, "/")
            menuId uint
        )
        //获取菜单ID
        menuId, err = systemService.SysAuthRule().GetIdByName(ctx, url)
        liberr.ErrIsNil(ctx, err)
        //获取用户所属角色对应的当前菜单的数据权限
        where, err = systemService.SysUser().GetDataWhere(ctx,
            systemService.Context().GetLoginUser(ctx),
            ent,
            menuId,
        )
        liberr.ErrIsNil(ctx, err)
        m = m.Where(where) //添加条件
        listRes.Total, err = m.Count()
        liberr.ErrIsNil(ctx, err, "获取总行数失败")
        if req.PageNum == 0 {
            req.PageNum = 1
        }
        listRes.CurrentPage = req.PageNum
        if req.PageSize == 0 {
            req.PageSize = consts.PageSize
        }
        order := "demo.id asc"
        if req.OrderBy != "" {
            order = req.OrderBy
        }
        var res []*model.DemoDataAuthListRes
        err = m.Page(req.PageNum, req.PageSize).Order(order).Scan(&res)
        liberr.ErrIsNil(ctx, err, "获取数据失败")
        listRes.List = make([]*model.DemoDataAuthListRes, len(res))
        for k, v := range res {
            listRes.List[k] = &model.DemoDataAuthListRes{
                Id:          v.Id,
                Title:       v.Title,
                CreatedUser: v.CreatedUser,
                CreatedBy:   v.CreatedBy,
                CreatedAt:   v.CreatedAt,
            }
        }
    })
    return
}

#修改model文件中,找到DemoDataAuthListRes结果提修改,添加查询字段表的别名:
type DemoDataAuthListRes struct {
    Id          uint                     `json:"id" dc:"" orm:"demo.id"`
    Title       string                   `json:"title" dc:"标题"`
    CreatedUser *systemModel.LinkUserRes `orm:"with:id=created_by" json:"createdUser"`
    CreatedBy   uint                     `json:"createdBy" dc:"创建人" orm:"demo.created_by"`
    CreatedAt   *gtime.Time              `json:"createdAt" dc:"创建时间" orm:"demo.created_at"`
}

在添加数据权限之前,可以看到后端控制台sql日志中的查询语句如下:

SELECT `id`,`title`,`created_by`,`updated_by`,`created_at`,`updated_at`,`deleted_at` FROM `demo_data_auth` WHERE `deleted_at` IS NULL ORDER BY `id` asc LIMIT 0,10

添加数据权限判断后生成的查询语句:

SELECT demo.* FROM `demo_data_auth` AS demo LEFT JOIN `sys_user` user ON (demo.created_by=user.id) WHERE ((demo.deleted_at is null) AND (user.id=31)) AND `demo`.`deleted_at` IS NULL AND `user`.`deleted_at` IS NULL ORDER BY `id` asc LIMIT 0,10

生成上面sql语句是因为我当前登录用户数据权限是仅本人数据权限只能查看自己添加的数据,可以看到查询条件中多了条件AND (user.id=31))

列表页面只能查询出两条数据:

修改一下数据权限为本部门及下级部门权限

修改当前登录用户部门为深圳总公司则他应该能访问所在部门及下级部门添加的数据

列表查询数据:

生成的查询语句:

SELECT demo.* FROM `demo_data_auth` AS demo LEFT JOIN `sys_user` user ON (demo.created_by
=user.id) WHERE ((demo.deleted_at is null) AND (user.dept_id IN(103,104,105,106,107,101))) AND `demo`.`deleted_at` IS NULL AND `user`.`deleted_at` IS NULL ORDER BY `id` asc LIMIT 0,10

可以看到查询条件已改变为:AND (user.dept_id IN(103,104,105,106,107,101)))

控制修改操作权限实例如下:

修改internal/app/demo/logic/demoDataAuth/demo_data_auth.go文件Edit方法内容:

func (s *sDemoDataAuth) Edit(ctx context.Context, req *model.DemoDataAuthEditReq) (err error) {
    err = g.Try(ctx, func(ctx context.Context) {
        //添加数据权限判断条件
        var (
            where g.Map
            ent   *entity.DemoDataAuth
            info  *model.DemoDataAuthInfoRes
            url    = gstr.TrimLeft(ghttp.RequestFromCtx(ctx).Request.URL.Path, "/")
            menuId uint
        )
        menuId, err = systemService.SysAuthRule().GetIdByName(ctx, url)
        liberr.ErrIsNil(ctx, err)
        where, err = systemService.SysUser().GetDataWhere(ctx,
            systemService.Context().GetLoginUser(ctx),
            ent,
            menuId,
        )
        liberr.ErrIsNil(ctx, err)
        info,err = s.GetById(ctx, req.Id)
        liberr.ErrIsNil(ctx,err)
        if info == nil{
            liberr.ErrIsNil(ctx,gerror.New("要修改的数据不存在"))
        }
        if !systemService.SysUser().HasAccessByDataWhere(ctx,where,info.CreatedBy){
            liberr.ErrIsNil(ctx,gerror.New("没有权限"))
        }
        _, err = dao.DemoDataAuth.Ctx(ctx).WherePri(req.Id).Update(do.DemoDataAuth{
            Title:     req.Title,
            UpdatedBy: systemService.Context().GetUserId(ctx),
        })
        liberr.ErrIsNil(ctx, err, "修改失败")
    })
    return
}

此时修改了没有修改权限的数据时提示没有权限

控制删除操作权限实例如下:

修改internal/app/demo/logic/demoDataAuth/demo_data_auth.go文件Delete方法内容:

func (s *sDemoDataAuth) Delete(ctx context.Context, ids []uint) (err error) {
    err = g.Try(ctx, func(ctx context.Context) {
        //添加数据权限判断条件
        var (
            where  g.Map
            ent    *entity.DemoDataAuth
            infos  []*model.DemoDataAuthInfoRes
            url    = gstr.TrimLeft(ghttp.RequestFromCtx(ctx).Request.URL.Path, "/")
            menuId uint
            createdBys []interface{}
        )
        menuId, err = systemService.SysAuthRule().GetIdByName(ctx, url)
        liberr.ErrIsNil(ctx, err)
        where, err = systemService.SysUser().GetDataWhere(ctx,
            systemService.Context().GetLoginUser(ctx),
            ent,
            menuId,
        )
        liberr.ErrIsNil(ctx, err)
        err = dao.DemoDataAuth.Ctx(ctx).Where(dao.DemoDataAuth.Columns().Id+" in (?)", ids).
            Fields(dao.DemoDataAuth.Columns().CreatedBy).Scan(&infos)
        liberr.ErrIsNil(ctx, err)
        if infos == nil {
            liberr.ErrIsNil(ctx, gerror.New("要删除的数据不存在"))
        }
        for _, i := range infos {
            createdBys = append(createdBys, i.CreatedBy)
        }
        if !systemService.SysUser().HasAccessByDataWhere(ctx, where, createdBys) {
            liberr.ErrIsNil(ctx, gerror.New("没有权限"))
        }
        _, err = dao.DemoDataAuth.Ctx(ctx).Delete(dao.DemoDataAuth.Columns().Id+" in (?)", ids)
        liberr.ErrIsNil(ctx, err, "删除失败")
    })
    return
}
作者:管理员  创建时间:2023-02-07 15:22
最后编辑:管理员  更新时间:2024-12-03 15:05