【学习】若依源码(前后端分离版)之 “ 获取角色权限信息及动态路由”

news2024/12/28 22:02:11

大型纪录片:学习若依源码(前后端分离版)之 “ 获取角色权限信息及动态路由”

  • 获取用户信息
  • 获取路由信息

承接上回,我们发现在login请求后面跟了两个请求,今天我们就来了解一下两个请求的含义。
图一

获取用户信息

先看 ‘/getInfo()’ 方法,代码如下:

/**
     * 获取用户信息
     * 
     * @return 用户信息
     */
    @GetMapping("getInfo")
    public AjaxResult getInfo()
    {
        SysUser user = SecurityUtils.getLoginUser().getUser();
        // 角色集合
        Set<String> roles = permissionService.getRolePermission(user);
        // 权限集合
        Set<String> permissions = permissionService.getMenuPermission(user);
        AjaxResult ajax = AjaxResult.success();
        ajax.put("user", user);
        ajax.put("roles", roles);
        ajax.put("permissions", permissions);
        return ajax;
    }

在方法里面,我们首先会去spring security里面获取该用户,然后在getRolePermission(user);里面判断该用户是不是管理员,如果是管理员就给予全部权限;不是则根据用户ID去查数据库给出对应的权限。再在service里进行分割处理。

 /**
     * 根据用户ID查询权限
     * 
     * @param userId 用户ID
     * @return 权限列表
     */
    @Override
    public Set<String> selectRolePermissionByUserId(Long userId)
    {
        List<SysRole> perms = roleMapper.selectRolePermissionByUserId(userId);
        Set<String> permsSet = new HashSet<>();
        for (SysRole perm : perms)
        {
            if (StringUtils.isNotNull(perm))
            {
                permsSet.addAll(Arrays.asList(perm.getRoleKey().trim().split(",")));
            }
        }
        return permsSet;
    }

这里来补充一些spring security的内容,下列方法怎么获取到登录的用户信息的呢?

SecurityUtils.getLoginUser().getUser();

打开封装的SecurityUtils,可以看到getLoginUser()的具体实现
图二
Spring Security 的 getAuthentication ().getPrincipal () 方法的作用是获取当前用户的信息。这个信息通常是一个 UserDetails 的实例,它包含了用户名、密码、角色等属性。可以通过这个方法来访问当前用户的相关数据,比如判断用户是否有某个权限或者显示用户的昵称等。

这个方法的底层原理是基于 Spring Security 的核心组件 SecurityContextHolder 和 SecurityContext。

说到这我们顺便回顾一下Spring Security 的登录认证流程大致是什么样子的:

  • 首先用户通过浏览器发送一个 POST 请求到 /login 接口,请求中包含了用户名和密码等参数。
  • 服务器端接收到请求后,会调用 UsernamePasswordAuthenticationFilter 这个过滤器来处理登录逻辑。这个过滤器会从请求中提取出用户名和密码,并构造一个 UsernamePasswordAuthenticationToken 对象,这个对象就封装了用户的认证信息。

觉得我讲的不够清楚的,可以移步到这里:Spring Security 登录流程;他讲的应该比我清楚一些。

获取路由信息

获取路由信息和获取用户信息思路差不多。来看代码:

    /**
     * 获取路由信息
     * 
     * @return 路由信息
     */
    @GetMapping("getRouters")
    public AjaxResult getRouters()
    {
        Long userId = SecurityUtils.getUserId();
        //查目录表Sys_menus,根据用户查菜单,生成动态路由
        List<SysMenu> menus = menuService.selectMenuTreeByUserId(userId);
        return AjaxResult.success(menuService.buildMenus(menus));
    }

可能这里你会有一点点疑问,为什么什么是查出整个用户,而下面是只查出用户的ID呢?

其实打开方法一路点点点就知道,若依在设计SysUser实体的时候写了一个方法为 ‘isAdmin()’ ,该方法就是专门用来判断是否用户为管理员的。

为什么查路由只需要ID,因为它真的就只需要ID,举个例子我们有一个用户表,一张权限表,我们理所应当会再设计一个连接表,用来存放两者对应的关系。查看mapper层代码我们可以发现
图三
其实他连接了很多张表,而这些表只需要一个用户ID去查就可以了。

查完数据,会在service层进行一个处理,何为动态路由?就是一个目录下面有很多一级菜单,一级菜单又有二级菜单……以此类推。

这里给出service层的代码截图,大家可以学学别人封装的思想,我觉得也蛮有意思的。
图四
该方法为根据父节点的ID获取所有子节点

图五
该方法为递归列表,及第二层及以下。

图六
该方法用于得到子节点列表。

图七
该方法用于判断是否有子节点。

然后就把整理好后的路由菜单封装成List返回到controller层。接着执行下一个方法,这个方法也很重要,前端的菜单分为菜单、目录等等,设置可见性等操作都是通过这个方法实现的,来看方法

/**
     * 构建前端路由所需要的菜单
     *
     * @param menus 菜单列表
     * @return 路由列表
     */
    @Override
    public List<RouterVo> buildMenus(List<SysMenu> menus) {
        List<RouterVo> routers = new LinkedList<RouterVo>();
        for (SysMenu menu : menus) {
            RouterVo router = new RouterVo();
            router.setHidden("1".equals(menu.getVisible()));
            router.setName(getRouteName(menu));
            router.setPath(getRouterPath(menu));
            router.setComponent(getComponent(menu));
            router.setQuery(menu.getQuery());
            router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache()), menu.getPath()));
            List<SysMenu> cMenus = menu.getChildren();
            if (!cMenus.isEmpty() && cMenus.size() > 0 && UserConstants.TYPE_DIR.equals(menu.getMenuType())) {
                router.setAlwaysShow(true);
                router.setRedirect("noRedirect");
                router.setChildren(buildMenus(cMenus));
            } else if (isMenuFrame(menu)) {
                router.setMeta(null);
                List<RouterVo> childrenList = new ArrayList<RouterVo>();
                RouterVo children = new RouterVo();
                children.setPath(menu.getPath());
                children.setComponent(menu.getComponent());
                children.setName(StringUtils.capitalize(menu.getPath()));
                children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache()), menu.getPath()));
                childrenList.add(children);
                router.setChildren(childrenList);
            } else if (menu.getParentId().intValue() == 0 && isInnerLink(menu)) {
                router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon()));
                router.setPath("/inner");
                List<RouterVo> childrenList = new ArrayList<RouterVo>();
                RouterVo children = new RouterVo();
                String routerPath = StringUtils.replaceEach(menu.getPath(), new String[]{Constants.HTTP, Constants.HTTPS}, new String[]{"", ""});
                children.setPath(routerPath);
                children.setComponent(UserConstants.INNER_LINK);
                children.setName(StringUtils.capitalize(routerPath));
                children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), menu.getPath()));
                childrenList.add(children);
                router.setChildren(childrenList);
            }
            routers.add(router);
        }
        return routers;
    }

这段代码是什么意思呢?这段代码是用来构建前端路由所需要的菜单的。它的主要逻辑是:

  • 遍历菜单列表,为每个菜单创建一个 RouterVo 对象,设置其属性,如是否隐藏,名称,路径,组件,查询参数,元数据等。
  • 如果菜单有子菜单,并且菜单类型是目录(UserConstants.TYPE_DIR),则递归调用 buildMenus 方法,将子菜单也转换为 RouterVo 对象,并添加到父菜单的 children 属性中。
  • 如果菜单是一个外部链接(isMenuFrame 方法判断),则将其元数据设置为 null,并创建一个新的 RouterVo 对象作为其子菜单,设置其路径,组件,名称,元数据等。
  • 如果菜单的父菜单 id 是 0,并且是一个内部链接(isInnerLink 方法判断),则将其路径设置为 “/inner”,并创建一个新的 RouterVo 对象作为其子菜单,设置其路径(去掉 http 或 https 前缀),组件(UserConstants.INNER_LINK),名称(首字母大写),元数据等。
  • 将创建好的 RouterVo 对象添加到路由列表中,并返回。

在完成过这两个请求之后,进入系统之后旁边的菜单栏就会对应显示出来,用户的权限和角色也将保存到前端,简便日后的一些操作。如果哪里有没讲清楚的地方欢迎评论留言。

那么以上就是唐某的一些理解。这次的分享就到这里了。记得一键三连~( •̀ ω •́ )✧

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/860523.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vulhub之Apache HTTPD 换行解析漏洞(CVE-2017-15715)

Apache HTTPD是一款HTTP服务器&#xff0c;它可以通过mod_php来运行PHP网页。其2.4.0~2.4.29版本中存在一个解析漏洞&#xff0c;在解析PHP时&#xff0c;1.php\x0A将被按照PHP后缀进行解析&#xff0c;导致绕过一些服务器的安全策略。 1、docker-compose build、docker-compo…

yolov5的报错

【定期水一期】 &#xff08;这个问题很抓马&#xff0c;可以看一下这篇文章&#xff1a;Git Bash 教程&#xff01;【不是所有人都会用Git】&#xff09; 一&#xff1a;没有cv2这个模块 解决方案&#xff1a; pip install opencv-python -i http://pypi.douban.com/simple/…

Java用方法实现数组拷贝

Java用方法实现数组拷贝 需求分析代码实现小结Time 需求分析 1.首先&#xff0c;考虑方法是否需要接收数据处理&#xff1f; 该方法的目的是拷贝数组&#xff0c;拷贝哪一个数组呢&#xff1f; 需要调用者传递 所以&#xff0c;参数应该是一个数组 2.接着&#xff0c;考虑方法是…

k8s常用资源管理

目录 Pod&#xff08;容器组&#xff09;&#xff1a;Pod是Kubernetes中最小的部署单元&#xff0c;可以包含一个或多个容器。Pod提供了一种逻辑上的封装&#xff0c;使得容器可以一起共享网络和存储资源 1、创建一个pod 2、pod管理 pod操作 Pod&#xff08;容器组&#xff…

单机游戏防破解方案解析

近年来&#xff0c;游戏市场用户规模趋于稳定&#xff0c;游戏市场进入了存量时代&#xff0c;各赛道“人满为患”&#xff0c;如何在一片红海中站稳脚跟成了厂商的必修课。 而在快节奏的社会环境下&#xff0c;脱离了网游社交粘性&#xff0c;主打清爽、自由的单机游戏&#…

软考圈地震!2023年下半年软考改为机考,报名时间推迟到9月4日

【1】通知原文 关于2023年下半年计算机软件资格考试有关工作调整的通知 各省、自治区、直辖市及计划单列市、新疆生产建设兵团&#xff0c;香港、澳门计算机软件资格考试考务管理机构: 为全面做好计算机软件资格考试安全防控工作&#xff0c;确保考试公正、公平。现将有关工…

【C语言学习】构造函数求出1到10、20到30、40到50的三个和

求出1到10、20到30、40到50的三个和 代码一&#xff1a;代码复制 #include<stdio.h> int main() {int i;int sum;for(i1,sum0; i<10; i){sum sum i;}printf("%d到%d的和是%d\n", 1, 10, sum);for(i20,sum0; i<30; i){sum sum i;}printf("%d到…

易服客工作室:如何创建有用的内容日历

利用技巧和工具优化您的内容营销效率和效果。创建一个内容日历&#xff0c;您的整个团队都会从中受益&#xff01; 欢迎来到熙熙攘攘、瞬息万变的内容营销世界&#xff0c;在这里&#xff0c;截止日期到来的速度比喝咖啡的猎豹还要快。 现在&#xff0c;想象一下在没有地图、…

家电用PCM板:市场现状研究分析与发展前景预测

家电PCM板属于一种兴起不久的功能性复合材料。属于家电复合外观材料中占比较大的一种。家电复合外观材料主要分为覆膜板&#xff08;VCM&#xff09;系列和有机涂层板&#xff08;PCM&#xff09;系列两大类&#xff1a;VCM系列表面复合各类功能性薄膜&#xff0c;可根据需要实…

湘大 XTU OJ 1214 A+B IV 题解:数位移动的本质+布尔变量标记+朴素模拟

一、链接 AB IV 二、题目 题目描述 小明喜欢做ab的算术&#xff0c;但是他经常忘记把末位对齐&#xff0c;再进行加&#xff0c;所以&#xff0c;经常会算错。 比如1213&#xff0c;他把12左移了1位&#xff0c;结果变成了133。 小明已经算了一些等式&#xff0c;请计算一下…

棒球游戏产业的发展·棒球1号位

棒球游戏产业的发展 1. 棒球游戏产业概述 棒球游戏产业的定义 棒球游戏产业是一个包罗万象的产业集群&#xff0c;涵盖了从基础设施到高端设备&#xff0c;从前沿技术研发到市场推广等各个环节。这个产业的繁荣得益于棒球运动的普及&#xff0c;人们对于棒球游戏的热情以及对…

0基础学C#笔记09:希尔排序法

文章目录 前言一、希尔排序的思想二、使用步骤总结前言 希尔排序可以说是插入排序的一种变种。无论是插入排序还是冒泡排序,如果数组的最大值刚好是在第一位,要将它挪到正确的位置就需要 n - 1 次移动。也就是说,原数组的一个元素如果距离它正确的位置很远的话,则需要与相…

linux cp -rpf指令

cp -rpf #强行递归复制/etc目录到/mist目录中&#xff0c;并保持源目录的权限等信息不变。 有点类似于打patch&#xff0c;不会改变已有的内容。

一次面试下来Android Framework 层的源码就问了4轮

说起字节跳动的这次面试经历&#xff0c;真的是现在都让我感觉背脊发凉&#xff0c;简直被面试官折磨的太难受了。虽然已经工作了七年&#xff0c;但是也只是纯粹的在写业务&#xff0c;对底层并没有一个很深的认识&#xff0c;这次面试经历直接的让我感受到我和那些一线大厂开…

揭秘!亚马逊美国站的热门品类有哪些?

做亚马逊跨境电商&#xff0c;做热门的品类是很最重要的&#xff0c;这样的市场需求量大&#xff0c;产品才能够更好的销售出去&#xff0c;不然的话选择冷门品类&#xff0c;就算你做到了第一&#xff0c;那销量一样不高。 在亚马逊跨境电商很多站点内都有热门品类&#xff0…

gateway做token校验

本文使用springcloud的gateway做token校验 登录的本质&#xff1a;拿用户名和密码 换 token。 token会返回给浏览器&#xff08;存储&#xff09;&#xff0c;当访问的时候&#xff0c;携带token 发起请求。 token校验图 引入redis依赖 <dependency><groupId>or…

vue3多条件搜索功能

搜索功能在后台管理页面中非常常见&#xff0c;本篇就着重讲一下vue3-admin-element框架中如何实现一个顶部多条件搜索功能 一、首先需要在vue页面的<template></template>中写入对应的结构 <!-- 搜索 --><div style"display: flex; justify-content…

HoG特征笔记

简介 HoG&#xff08;Histogram of Oriented Gradient&#xff09;&#xff0c;方向梯度直方图。HoG特征是一种特征描述符。它通过计算和统计图像局部区域的梯度方向直方图来描述特征。 HoG基于的底层原理是图像中局部目标的表象和形状&#xff08;appearance and shape&#x…

Java中VO,BO,PO,DO,DTO的区别

术语解释&#xff1a; VO&#xff08; View Object&#xff09;&#xff1a;显示层对象&#xff0c;通常是Web向模板渲染引擎层传输的对象。 BO&#xff08; Business Object&#xff09;&#xff1a;业务对象。 由Service层输出的封装业务逻辑的对象。 DO&#xff08; Data…

华为新版ENSP PRO模拟器测评:性能表现与功能扩展一览

一、引言 在网络领域不断涌现的新技术和复杂的网络拓扑要求&#xff0c;推动了网络设备模拟器的持续发展和创新。华为作为一家领先的通信技术解决方案提供商&#xff0c;不断致力于为网络工程师和技术从业人员提供更优秀的仿真环境。最近&#xff0c;华为推出了ensp pro模拟器的…