推广

SpringSecurity权限管理系统实战—九、数据权限的配置

iseeyu3年前 (2024-02-21)推广128

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

分别是岗位表,部门表,用户岗位关联表和角色部门关联表

my_user表中添加dept_id字段。my_role表中添加data_scpoe字段。前一个很好理解,就是部门的id,后一个代表的就是角色的数据权限范围
(这篇文章很难写,文章所代表的代码内容也很难写,大家想要理解透彻还是要从源码里看,自己做一遍才能真正的理解)

三、效果

效果

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

效果就是这样,代码也不贴了,这部分逻辑有点复杂,代码量很大,可以自行去源码中查看。

四、实现

这里只是介绍下如何实现数据权限,参考了若依项目中的实现方法
首先我们自定义一个注解

/**
 * 数据权限过滤注解
 * @author codermy
 * @createTime 2020/8/22
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataPermission {
    /**
     * 部门表的别名
     */
    public String deptAlias() default "";

    /**
     * 用户表的别名
     */
    public String userAlias() default "";
}

再定义一个切面类

    /**
 * 数据过滤处理
 * @author codermy
 * @createTime 2020/8/22
 */
@Aspect
@Component
public class DataScopeAspect {

    @Autowired
    public RoleUserService roleUserService;
    /**
     * 全部数据权限
     */
    public static final String DATA_SCOPE_ALL = "1";

    /**
     * 自定数据权限
     */
    public static final String DATA_SCOPE_CUSTOM = "2";

    /**
     * 部门数据权限
     */
    public static final String DATA_SCOPE_DEPT = "3";

    /**
     * 部门及以下数据权限
     */
    public static final String DATA_SCOPE_DEPT_AND_CHILD = "4";

    /**
     * 仅本人数据权限
     */
    public static final String DATA_SCOPE_SELF = "5";

    /**
     * 数据权限过滤关键字
     */
    public static final String DATA_SCOPE = "dataScope";

    /**
     * 配置织入点
     */
    @Pointcut("@annotation(com.codermy.myspringsecurityplus.admin.annotation.DataPermission)")
    public void dataScopePointCut()
    {
    }

    @Before("dataScopePointCut()")
    public void doBefore(JoinPoint point) throws Throwable
    {
        handleDataScope(point);
    }

    protected void handleDataScope(final JoinPoint joinPoint)
    {
        // 获得注解
        DataPermission controllerDataScope = getAnnotationLog(joinPoint);
        if (controllerDataScope == null)
        {
            return;
        }
        // 获取当前的用户
        JwtUserDto currentUser = SecurityUtils.getCurrentUser();
        if (currentUser != null)
        {
            // 如果是超级管理员,则不过滤数据
            if (!currentUser.isAdmin())
            {
                dataScopeFilter(joinPoint, currentUser, controllerDataScope.deptAlias(),
                        controllerDataScope.userAlias());
            }
        }
    }

    /**
     * 数据范围过滤
     *
     * @param joinPoint 切点
     * @param user 用户
     * @param deptAlias 部门别名
     * @param userAlias 用户别名
     */
    public static void dataScopeFilter(JoinPoint joinPoint, JwtUserDto user, String deptAlias, String userAlias)
    {
        StringBuilder sqlString = new StringBuilder();

        for (MyRole role : user.getRoleInfo())
        {
            String dataScope = role.getDataScope();
            if (DATA_SCOPE_ALL.equals(dataScope))
            {
                sqlString = new StringBuilder();
                break;
            }
            else if (DATA_SCOPE_CUSTOM.equals(dataScope))
            {
                sqlString.append(StrUtil.format(
                        " OR {}.id IN ( SELECT dept_id FROM my_role_dept WHERE role_id = {} ) ", deptAlias,
                        role.getId()));
            }
            else if (DATA_SCOPE_DEPT.equals(dataScope))
            {
                sqlString.append(StrUtil.format(" OR {}.id = {} ", deptAlias, user.getMyUser().getDeptId()));
            }
            else if (DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope))
            {
                sqlString.append(StrUtil.format(
                        " OR {}.id IN ( SELECT id FROM my_dept WHERE id = {} or find_in_set( {} , ancestors ) )",
                        deptAlias, user.getMyUser().getDeptId(), user.getMyUser().getDeptId()));
            }
            else if (DATA_SCOPE_SELF.equals(dataScope))
            {
                if (StrUtil.isNotBlank(userAlias))
                {
                    sqlString.append(StrUtil.format(" OR {}.id = {} ", userAlias, user.getMyUser().getId()));
                }
                else
                {
                    // 数据权限为仅本人且没有userAlias别名不查询任何数据
                    sqlString.append(" OR 1=0 ");
                }

            }
        }
        if (StrUtil.isNotBlank(sqlString.toString()))
        {
            BaseEntity baseEntity;
            for (int i = 0;i < joinPoint.getArgs().length ;i++ ){
                if (joinPoint.getArgs()[i] instanceof BaseEntity){
                    baseEntity= (BaseEntity) joinPoint.getArgs()[i];
                    baseEntity.getParams().put(DATA_SCOPE, " AND (" + sqlString.substring(4) + ")");
                }
            }

        }
    }

    /**
     * 是否存在注解,如果存在就获取
     */
    private DataPermission getAnnotationLog(JoinPoint joinPoint)
    {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();

        if (method != null)
        {
            return method.getAnnotation(DataPermission.class);
        }
        return null;
    }
}

解释一下这个切面类的作用就是:
当你在ServiceImpl的某个方法上定义了这个注解时,它就会获取当前登录用户的角色的dataScope(就是数据范围),然后比较它的值,将相应的sql语句存入baseEntity的params中

然后我们只需要在对于需要配置数据权限的mapper.xml中添加${params.dataScope}

在这里插入图片描述

再在调用此方法的service方法上添加注解@DataPermission(deptAlias = “d”, userAlias = “u”)
即可

在这里插入图片描述

这里我在BaseEntity中添加了一个params属性来用于存放数据权限的sql

在这里插入图片描述

这样当我们需要调用这个sql时,如果未过滤权限时,sql是这样的

SELECT u.id, u.dept_id, u.user_name, u.password, u.nick_name
    , u.phone, u.email, u.status, u.create_time, u.update_time
FROM my_user u
    LEFT JOIN my_dept d ON u.dept_id = d.id
WHERE u.dept_id = ?
    OR u.dept_id IN (
        SELECT e.id
        FROM my_dept e
        WHERE FIND_IN_SET(?, ancestors)
    )
ORDER BY u.id

如果我们给这个角色的数据权限种类是自定数据权限,sql就会是下面这样

SELECT u.id, u.dept_id, u.user_name, u.password, u.nick_name
    , u.phone, u.email, u.status, u.create_time, u.update_time
FROM my_user u
    LEFT JOIN my_dept d ON u.dept_id = d.id
WHERE (u.dept_id = ?
        OR u.dept_id IN (
            SELECT e.id
            FROM my_dept e
            WHERE FIND_IN_SET(?, ancestors)
        ))
    AND d.id IN (
        SELECT dept_id
        FROM my_role_dept
        WHERE role_id = 2
    )
ORDER BY u.id

那么如果我们给角色 ‘普通用户’如下数据权限

在这里插入图片描述

那么当我们登录该角色的用户时,便只能访问到相应部门下的用户信息。

在这里插入图片描述

在这里插入图片描述

当我们再在部门的相应方法和sql上再添加上注解时过滤语句时,那么效果就是这样的

在这里插入图片描述

在这里插入图片描述

gitee和github中同步更新源码

扫描二维码推送至手机访问。

版权声明:本文由西安泽虎代运营发布,如需转载请注明出处。

转载请注明出处https://www.0291.com.cn/post/57538.html

相关文章

西安企业做百度推广,一个月花三千和花三万到底差在哪?

4|最近跟几个西安的老板聊天,发现一个挺有意思的现象:同样做百度推广,有人一个月花三千块,询盘不断;有人一个月砸三万,水花都没见着。问他们区别在哪,大多数人说不清楚,只知道'钱花了,没效果'。 5| 6|百度推广这东西,说复杂也复杂,说简单也简单。核心就一件事:让你的潜在客户搜某个词的时候,你的信息...

我想当策划,大学应该选什么专业?

我想当策划,大学应该选什么专业?

学,广告,传播,公关,这些专业其实都可以。另外也可以学像汉语言文学,以及一些跟文学相关的一些专业,会对你找工作有帮助。但是,你想从事这个这份职业,除了专业的学习之外,更多的是,你要在上学的时候积极参与一些更营销策划相关的社会实践。比如说你可以做一些兼职,比如说帮别人去写稿,...

服装市场营销策略分析,“定位不慎满盘皆输”

服装市场营销策略分析,“定位不慎满盘皆输”

不同的区域需要不同的策略,而不同的营销策略需要不同的销售思路来配合。因此,在研究女装产品销售思路之前,最好先对于市场与营销策略做一次深入地了解。1.市场区域化(market segmentation):目标营销的第一步,是将整个市场拆分成若干个同性质的小市场。2.目标市场的...

晚间悦读丨你的思维方式,决定你的人生高度!

晚间悦读丨你的思维方式,决定你的人生高度!

越长大,越发现,能够决定你人生高度的,往往是你的认知层次。 你的认知在哪个层级,你的人生就处在什么状态。你认知的高度,决定了你人生的高度。 那如何才能升级方式、提升认知能力呢?可以从这三个方面做出改变。 NO. 1 改变态度 有人...

编写项目营销策划方案六大要点

编写项目营销策划方案六大要点

现在商业发展非常迅速,的需求非常的大,但是要做好营销策划是有一定难度的,我把自己做营销策划的一些体会在这里分享给朋友们。营销策划方案六大要点我们先说项目营销策划方案这个话题。大部分的营销策划人都是在企业里工作,大部分项目之初都是来源于一个想法,创始人、老板或者创始团队的一个...

【商场营销策划】如何进行商场营销策划?

【商场营销策划】如何进行商场营销策划?

商场是策划者们关注的永恒话题,那么究竟该如何作好商场营销策划呢?掌握以下这几点营销策略设计原则,至关重要!1.义利兼顾的原则。商场在获取利润的同时要充分考虑到消费者的合法利益和商场的长远利益。在作商场活动营销策略方案的时候应该将这一点作为首要的原则。对商场有利而对顾客不利的...

现在,非常期待与您的又一次邂逅

我们努力让每一部企业宣传片和抖音短视频成为商业大片