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

编程入门 行业动态 更新时间:2024-10-28 09:27:59

【学习】若依源码(前后端分离版)之 “ 获取角色权限信息及动态<a href=https://www.elefans.com/category/jswz/34/1771390.html style=路由”"/>

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

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

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

承接上回,我们发现在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 权限列表*/@Overridepublic 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 路由列表*/@Overridepublic 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 对象添加到路由列表中,并返回。

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

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

更多推荐

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

本文发布于:2024-03-13 04:19:09,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1733168.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:路由   源码   后端   角色   权限

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!