推广

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

iseeyu2年前 (2024-02-21)推广112

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

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

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

相关文章

淘宝开不了店怎么回事,淘宝店开店后一直不用(2021手机淘宝怎么进自己店铺)

淘宝开不了店怎么回事,淘宝店开店后一直不用(2021手机淘宝怎么进自己店铺)

点“免费注册”,可以选择手机号码注册或邮箱注册,我们一般选择“邮箱注册”,填好一切资料,点击“同意协议并提交注册信息”,如果没有意外的话网站提示注册成功。...

【抖友必看】写完这篇卸载抖音:抖音为啥会让人上瘾。

【抖友必看】写完这篇卸载抖音:抖音为啥会让人上瘾。

本文将分析抖音:她为什么如此着迷、让人上瘾?为什么如此爱不释手、让人欲罢不能? 就短视频来说,因为曾经专门做短视频营销的缘故,对美拍、秒拍、火山、快手等短视频平台有颇多研究,对内容、视频达人也有些深入了解。但多是停留在工作层面,并没有发自内心喜欢去看,抖音却正中我下怀。 作...

如何在腾讯投放搜索竞价广告??

如何在腾讯投放搜索竞价广告??

  近期,我们发现腾讯上线了搜索竞价广告,团队马上决定快速测试一下。 于是我们就在日常投放信息流的基础上,加投了一些搜索竞价广告,测试时间为一个月,发现搜索竞价广告转化数提升了41%,成本也下降了23%。效果远远超出我们的预期。 我复盘了我们的投放过程,发现有4点经验对于效...

搜索引擎算法演变的几个阶段。

搜索引擎算法演变的几个阶段。

SEO直到现在停止仍然是网络营销范畴十分重要的营销手法之一,不论你的企业是做什么的,或许你是个人,只需你学会了SEO之后,你就可以不花一块钱,把你的关键词排在查找引擎前面,取得海量的精准方针客户。 在SEO范畴,算法一向都是站长们头疼的工作,并且十分多的站长心里都很浮躁,每天都想去研...

企业为什么要做抖音运营?

原标题:企业为什么要做抖音运营? 抖音运营可以帮企业降低管理成本;一般企业的业务都和短视频没有太大的关系,所以如果想自己运营抖音账号,就需要重新招聘人才组建团队,意味着多了一个部门,也增加了管理的难度。当然,正确的想法是将这项不熟悉的业务外包出去,交给专门做抖音短视频运营的公司去做,也就不会增...

白杨SEO:网络推广软文怎么写?手把手教你如何写软文!

白杨SEO:网络推广软文怎么写?手把手教你如何写软文!

前言:这是白杨公众号原创第338篇。为什么想到写这个?一个是受涛哥一篇文章标题启发,另一个是让关注白杨SEO公众号的SEO、流量、新媒体从业新人学习如何写软文。开门见山,不藏了,其实以下公众号文章都是软文:白杨SEO:公司企业网站建设制作是什么及建站注意事项!【必看】白杨S...

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

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