自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

手把手教你搞定菜單權(quán)限設(shè)計(jì),精確到按鈕級(jí)別,建議收藏

開(kāi)發(fā) 項(xiàng)目管理
在實(shí)際的項(xiàng)目開(kāi)發(fā)過(guò)程中,菜單權(quán)限功能可以說(shuō)是后端管理系統(tǒng)中必不可少的一個(gè)環(huán)節(jié),根據(jù)業(yè)務(wù)的復(fù)雜度,設(shè)計(jì)的時(shí)候可深可淺,但無(wú)論怎么變化,設(shè)計(jì)的思路基本都是圍繞著用戶(hù)、角色、菜單進(jìn)行相應(yīng)的擴(kuò)展。

 一、介紹

在實(shí)際的項(xiàng)目開(kāi)發(fā)過(guò)程中,菜單權(quán)限功能可以說(shuō)是后端管理系統(tǒng)中必不可少的一個(gè)環(huán)節(jié),根據(jù)業(yè)務(wù)的復(fù)雜度,設(shè)計(jì)的時(shí)候可深可淺,但無(wú)論怎么變化,設(shè)計(jì)的思路基本都是圍繞著用戶(hù)、角色、菜單進(jìn)行相應(yīng)的擴(kuò)展。

[[331842]]

今天小編就和大家一起來(lái)討論一下,怎么設(shè)計(jì)一套可以精確到按鈕級(jí)別的菜單權(quán)限功能,廢話不多說(shuō),直接開(kāi)擼!

二、數(shù)據(jù)庫(kù)設(shè)計(jì)

先來(lái)看一下,用戶(hù)、角色、菜單表對(duì)應(yīng)的ER圖,如下:

 

其中,用戶(hù)和角色是多對(duì)多的關(guān)系,角色與菜單也是多對(duì)多的關(guān)系,用戶(hù)通過(guò)角色來(lái)關(guān)聯(lián)到菜單,當(dāng)然也有的業(yè)務(wù)系統(tǒng)菜單權(quán)限模型,是可以直接通過(guò)用戶(hù)關(guān)聯(lián)到菜單,對(duì)菜單權(quán)限可以直接控制到用戶(hù)級(jí)別,不過(guò)這個(gè)都不是問(wèn)題,這個(gè)也可以進(jìn)行擴(kuò)展。

對(duì)于用戶(hù)、角色表比較簡(jiǎn)單,下面,我們重點(diǎn)來(lái)看看菜單表的設(shè)計(jì),如下:

 

可以看到,整個(gè)菜單表就是一個(gè)樹(shù)型結(jié)構(gòu),關(guān)鍵字段說(shuō)明:

  • menu_code:菜單編碼,用于后端權(quán)限控制
  • parent_id:菜單父節(jié)點(diǎn)ID,方便遞歸遍歷菜單
  • node_type:節(jié)點(diǎn)類(lèi)型,可以是文件夾、頁(yè)面或者按鈕類(lèi)型
  • link_url:頁(yè)面對(duì)應(yīng)的地址,如果是文件夾或者按鈕類(lèi)型,可以為空
  • level:菜單樹(shù)的層次,以便于查詢(xún)指定層級(jí)的菜單
  • path:樹(shù)id的路徑,主要用于存放從根節(jié)點(diǎn)到當(dāng)前樹(shù)的父節(jié)點(diǎn)的路徑,逗號(hào)分隔,想要找父節(jié)點(diǎn)會(huì)特別快

為了后面方便開(kāi)發(fā),我們先創(chuàng)建一個(gè)名為menu_auth_db的數(shù)據(jù)庫(kù),初始腳本如下:

  1. CREATE DATABASE IF NOT EXISTS menu_auth_db default charset utf8mb4 COLLATE utf8mb4_unicode_ci; 
  2.  
  3. CREATE TABLE menu_auth_db.tb_user ( 
  4.   id bigint(20) unsigned NOT NULL COMMENT '消息給過(guò)來(lái)的ID'
  5.   mobile varchar(20) NOT NULL DEFAULT '' COMMENT '手機(jī)號(hào)'
  6.   name varchar(100) NOT NULL DEFAULT '' COMMENT '姓名'
  7.   password varchar(128) NOT NULL DEFAULT '' COMMENT '密碼'
  8.   is_delete tinyint(4) NOT NULL DEFAULT '0' COMMENT '是否刪除 1:已刪除;0:未刪除'
  9.   PRIMARY KEY (id), 
  10.   KEY idx_name (name) USING BTREE, 
  11.   KEY idx_mobile (mobile) USING BTREE 
  12. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用戶(hù)表'
  13.  
  14. CREATE TABLE menu_auth_db.tb_user_role ( 
  15.   id bigint(20) unsigned NOT NULL COMMENT '主鍵'
  16.   user_id bigint(20) NOT NULL COMMENT '用戶(hù)ID'
  17.   role_id bigint(20) NOT NULL COMMENT '角色I(xiàn)D'
  18.   PRIMARY KEY (id), 
  19.   KEY idx_user_id (user_id) USING BTREE, 
  20.   KEY idx_role_id (role_id) USING BTREE 
  21. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用戶(hù)角色表'
  22.  
  23. CREATE TABLE menu_auth_db.tb_role ( 
  24.   id bigint(20) unsigned NOT NULL COMMENT '主鍵'
  25.   code varchar(100) NOT NULL DEFAULT '' COMMENT '編碼'
  26.   name varchar(100) NOT NULL DEFAULT '' COMMENT '名稱(chēng)'
  27.   is_delete tinyint(4) NOT NULL DEFAULT '0' COMMENT '是否刪除 1:已刪除;0:未刪除'
  28.   PRIMARY KEY (id), 
  29.   KEY idx_code (code) USING BTREE, 
  30.   KEY idx_name (name) USING BTREE 
  31. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='角色表'
  32.  
  33.  
  34. CREATE TABLE menu_auth_db.tb_role_menu ( 
  35.   id bigint(20) unsigned NOT NULL COMMENT '主鍵'
  36.   role_id bigint(20) NOT NULL COMMENT '角色I(xiàn)D'
  37.   menu_id bigint(20) NOT NULL COMMENT '菜單ID'
  38.   PRIMARY KEY (id), 
  39.   KEY idx_role_id (role_id) USING BTREE, 
  40.   KEY idx_menu_id (menu_id) USING BTREE 
  41. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='角色菜單關(guān)系表'
  42.  
  43.  
  44. CREATE TABLE menu_auth_db.tb_menu ( 
  45.   id bigint(20) NOT NULL COMMENT '主鍵'
  46.   name varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '名稱(chēng)'
  47.   menu_code varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '菜單編碼'
  48.   parent_id bigint(20) DEFAULT NULL COMMENT '父節(jié)點(diǎn)'
  49.   node_type tinyint(4) NOT NULL DEFAULT '1' COMMENT '節(jié)點(diǎn)類(lèi)型,1文件夾,2頁(yè)面,3按鈕'
  50.   icon_url varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '圖標(biāo)地址'
  51.   sort int(11) NOT NULL DEFAULT '1' COMMENT '排序號(hào)'
  52.   link_url varchar(500) COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '頁(yè)面對(duì)應(yīng)的地址'
  53.   level int(11) NOT NULL DEFAULT '0' COMMENT '層次'
  54.   path varchar(2500) COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '樹(shù)id的路徑 整個(gè)層次上的路徑id,逗號(hào)分隔,想要找父節(jié)點(diǎn)特別快'
  55.   is_delete tinyint(4) NOT NULL DEFAULT '0' COMMENT '是否刪除 1:已刪除;0:未刪除'
  56.   PRIMARY KEY (id) USING BTREE, 
  57.   KEY idx_parent_id (parent_id) USING BTREE 
  58. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='菜單表'

三、后端開(kāi)發(fā)

菜單權(quán)限模塊的數(shù)據(jù)庫(kù)設(shè)計(jì),一般5張表就可以搞定,真正有點(diǎn)復(fù)雜的地方在于數(shù)據(jù)的寫(xiě)入和渲染,當(dāng)然如果老板突然讓你來(lái)開(kāi)發(fā)一套菜單權(quán)限系統(tǒng),我們也沒(méi)必要慌張,下面,我們一起來(lái)看看后端應(yīng)該如何開(kāi)發(fā)。

3.1、創(chuàng)建項(xiàng)目

為了方便快捷,小編我采用的是springboot+mybatisPlus組件來(lái)快速開(kāi)發(fā),直接利用mybatisPlus官方提供的快速生成代碼的demo,一鍵生成所需的dao、service、web層的代碼,結(jié)果如下:

 

3.2、編寫(xiě)菜單添加服務(wù)

  1. @Override 
  2. public void addMenu(Menu menu) { 
  3.     //如果插入的當(dāng)前節(jié)點(diǎn)為根節(jié)點(diǎn),parentId指定為0 
  4.     if(menu.getParentId().longValue() == 0){ 
  5.         menu.setLevel(1);//根節(jié)點(diǎn)層級(jí)為1 
  6.         menu.setPath(null);//根節(jié)點(diǎn)路徑為空 
  7.     }else
  8.         Menu parentMenu = baseMapper.selectById(menu.getParentId()); 
  9.         if(parentMenu == null){ 
  10.             throw new CommonException("未查詢(xún)到對(duì)應(yīng)的父節(jié)點(diǎn)"); 
  11.         } 
  12.         menu.setLevel(parentMenu.getLevel().intValue() + 1); 
  13.         if(StringUtils.isNotEmpty(parentMenu.getPath())){ 
  14.             menu.setPath(parentMenu.getPath() + "," + parentMenu.getId()); 
  15.         }else
  16.             menu.setPath(parentMenu.getId().toString()); 
  17.         } 
  18.     } 
  19.     //可以使用雪花算法,生成ID 
  20.     menu.setId(System.currentTimeMillis()); 
  21.     super.save(menu); 

新增菜單比較簡(jiǎn)單,直接將數(shù)據(jù)插入即可,需要注意的地方是parent_id、level、path,這三個(gè)字段的寫(xiě)入,如果新建的是根節(jié)點(diǎn),默認(rèn)parent_id為0,方便后續(xù)遞歸遍歷。

3.3、編寫(xiě)菜單后端查詢(xún)服務(wù)

  • 新建一個(gè)菜單視圖實(shí)體類(lèi)
  1. @Data 
  2. @EqualsAndHashCode(callSuper = false
  3. @Accessors(chain = true
  4. public class MenuVo implements Serializable { 
  5.  
  6.     private static final long serialVersionUID = -4559267810907997111L; 
  7.  
  8.     /** 
  9.      * 主鍵 
  10.      */ 
  11.     private Long id; 
  12.  
  13.     /** 
  14.      * 名稱(chēng) 
  15.      */ 
  16.     private String name
  17.  
  18.     /** 
  19.      * 菜單編碼 
  20.      */ 
  21.     private String menuCode; 
  22.  
  23.     /** 
  24.      * 父節(jié)點(diǎn) 
  25.      */ 
  26.     private Long parentId; 
  27.  
  28.     /** 
  29.      * 節(jié)點(diǎn)類(lèi)型,1文件夾,2頁(yè)面,3按鈕 
  30.      */ 
  31.     private Integer nodeType; 
  32.  
  33.     /** 
  34.      * 圖標(biāo)地址 
  35.      */ 
  36.     private String iconUrl; 
  37.  
  38.     /** 
  39.      * 排序號(hào) 
  40.      */ 
  41.     private Integer sort; 
  42.  
  43.     /** 
  44.      * 頁(yè)面對(duì)應(yīng)的地址 
  45.      */ 
  46.     private String linkUrl; 
  47.  
  48.     /** 
  49.      * 層次 
  50.      */ 
  51.     private Integer level
  52.  
  53.     /** 
  54.      * 樹(shù)id的路徑 整個(gè)層次上的路徑id,逗號(hào)分隔,想要找父節(jié)點(diǎn)特別快 
  55.      */ 
  56.     private String path; 
  57.  
  58.     /** 
  59.      * 子菜單集合 
  60.      */ 
  61.     List<MenuVo> childMenu; 
  • 編寫(xiě)菜單查詢(xún)服務(wù),使用遞歸重新封裝菜單視圖
  1. @Override 
  2. public List<MenuVo> queryMenuTree() { 
  3.     Wrapper queryObj = new QueryWrapper<>().orderByAsc("level","sort"); 
  4.     List<Menu> allMenu = super.list(queryObj); 
  5.  // 0L:表示根節(jié)點(diǎn)的父ID 
  6.     List<MenuVo> resultList = transferMenuVo(allMenu, 0L); 
  7.     return resultList; 
  8. /** 
  9.  * 封裝菜單視圖 
  10.  * @param allMenu 
  11.  * @param parentId 
  12.  * @return 
  13.  */ 
  14. private List<MenuVo> transferMenuVo(List<Menu> allMenu, Long parentId){ 
  15.     List<MenuVo> resultList = new ArrayList<>(); 
  16.     if(!CollectionUtils.isEmpty(allMenu)){ 
  17.         for (Menu source : allMenu) { 
  18.             if(parentId.longValue() == source.getParentId().longValue()){ 
  19.                 MenuVo menuVo = new MenuVo(); 
  20.                 BeanUtils.copyProperties(source, menuVo); 
  21.                 //遞歸查詢(xún)子菜單,并封裝信息 
  22.                 List<MenuVo> childList = transferMenuVo(allMenu, source.getId()); 
  23.                 if(!CollectionUtils.isEmpty(childList)){ 
  24.                     menuVo.setChildMenu(childList); 
  25.                 } 
  26.                 resultList.add(menuVo); 
  27.             } 
  28.         } 
  29.     } 
  30.     return resultList; 

編寫(xiě)一個(gè)菜單樹(shù)查詢(xún)接口,如下:

  1. @RestController 
  2. @RequestMapping("/menu"
  3. public class MenuController { 
  4.  
  5.     @Autowired 
  6.     private MenuService menuService; 
  7.  
  8.     @PostMapping(value = "/queryMenuTree"
  9.     public List<MenuVo> queryTreeMenu(){ 
  10.         return menuService.queryMenuTree(); 
  11.     } 

為了便于演示,我們先初始化7條數(shù)據(jù),如下圖:

 

其中最后三條是按鈕類(lèi)型,等下會(huì)用于后端權(quán)限控制,接口查詢(xún)結(jié)果如下:

 

這個(gè)服務(wù)是針對(duì)后端管理界面查詢(xún)的,會(huì)將所有的菜單全部查詢(xún)出來(lái)以便于進(jìn)行管理,展示結(jié)果類(lèi)似如下圖:

 

這個(gè)圖片截圖于小編正在開(kāi)發(fā)的一個(gè)項(xiàng)目,內(nèi)容可能不一致,但是數(shù)據(jù)結(jié)構(gòu)基本都是一致的。

3.4、編寫(xiě)用戶(hù)菜單權(quán)限查詢(xún)服務(wù)

在上面,我們介紹到了用戶(hù)通過(guò)角色來(lái)關(guān)聯(lián)菜單,因此,很容易想到,流程如下:

  • 第一步:先通過(guò)用戶(hù)查詢(xún)到對(duì)應(yīng)的角色;
  • 第二步:然后再通過(guò)角色查詢(xún)到對(duì)應(yīng)的菜單;
  • 第三步:最后將菜單查詢(xún)出來(lái)之后進(jìn)行渲染;

實(shí)現(xiàn)過(guò)程相比菜單查詢(xún)服務(wù)多了前2個(gè)步驟,過(guò)程如下:

  1. @Override 
  2. public List<MenuVo> queryMenus(Long userId) { 
  3.     //1、先查詢(xún)當(dāng)前用戶(hù)對(duì)應(yīng)的角色 
  4.     Wrapper queryUserRoleObj = new QueryWrapper<>().eq("user_id", userId); 
  5.     List<UserRole> userRoles = userRoleService.list(queryUserRoleObj); 
  6.     if(!CollectionUtils.isEmpty(userRoles)){ 
  7.         //2、通過(guò)角色查詢(xún)菜單(默認(rèn)取第一個(gè)角色) 
  8.         Wrapper queryRoleMenuObj = new QueryWrapper<>().eq("role_id", userRoles.get(0).getRoleId()); 
  9.         List<RoleMenu> roleMenus = roleMenuService.list(queryRoleMenuObj); 
  10.         if(!CollectionUtils.isEmpty(roleMenus)){ 
  11.             Set<Long> menuIds = new HashSet<>(); 
  12.             for (RoleMenu roleMenu : roleMenus) { 
  13.                 menuIds.add(roleMenu.getMenuId()); 
  14.             } 
  15.             //查詢(xún)對(duì)應(yīng)的菜單 
  16.             Wrapper queryMenuObj = new QueryWrapper<>().in("id", new ArrayList<>(menuIds)); 
  17.             List<Menu> menus = super.list(queryMenuObj); 
  18.             if(!CollectionUtils.isEmpty(menus)){ 
  19.                 //將菜單下對(duì)應(yīng)的父節(jié)點(diǎn)也一并全部查詢(xún)出來(lái) 
  20.                 Set<Long> allMenuIds = new HashSet<>(); 
  21.                 for (Menu menu : menus) { 
  22.                     allMenuIds.add(menu.getId()); 
  23.                     if(StringUtils.isNotEmpty(menu.getPath())){ 
  24.                         String[] pathIds = StringUtils.split(",", menu.getPath()); 
  25.                         for (String pathId : pathIds) { 
  26.                             allMenuIds.add(Long.valueOf(pathId)); 
  27.                         } 
  28.                     } 
  29.                 } 
  30.                 //3、查詢(xún)對(duì)應(yīng)的所有菜單,并進(jìn)行封裝展示 
  31.                 List<Menu> allMenus = super.list(new QueryWrapper<Menu>().in("id", new ArrayList<>(allMenuIds))); 
  32.                 List<MenuVo> resultList = transferMenuVo(allMenus, 0L); 
  33.                 return resultList; 
  34.             } 
  35.         } 
  36.  
  37.     } 
  38.     return null
  • 編寫(xiě)一個(gè)用戶(hù)菜單查詢(xún)接口,如下:
  1. @PostMapping(value = "/queryMenus"
  2. public List<MenuVo> queryMenus(Long userId){ 
  3.  //查詢(xún)當(dāng)前用戶(hù)下的菜單權(quán)限 
  4.     return menuService.queryMenus(userId); 

有的同學(xué),可能覺(jué)得沒(méi)必要存放path這個(gè)字段,的確在某些場(chǎng)景下不需要。

為什么要存放這個(gè)字段呢?

小編在跟前端進(jìn)行對(duì)接的時(shí)候,發(fā)現(xiàn)這么一個(gè)問(wèn)題,有些前端的樹(shù)型組件,在勾選子集的時(shí)候,不會(huì)將對(duì)應(yīng)的父ID傳給后端,例如,我在勾選【列表查詢(xún)】的時(shí)候,前端無(wú)法將父節(jié)點(diǎn)【菜單管理】ID也傳給后端,所有后端實(shí)際存放的是一個(gè)尾節(jié)點(diǎn),需要一個(gè)字段path,來(lái)存放節(jié)點(diǎn)對(duì)應(yīng)的父節(jié)點(diǎn)路徑。

 

其實(shí),前端也可以傳,只不過(guò)需要修改組件的屬性,前端修改完成之后,樹(shù)型組件就無(wú)法全選,不滿(mǎn)足業(yè)務(wù)需求。

所以,有些時(shí)候得根據(jù)實(shí)際得情況來(lái)進(jìn)行取舍。

3.5、編寫(xiě)后端權(quán)限控制

后端進(jìn)行權(quán)限控制目標(biāo),主要是為了防止無(wú)權(quán)限的用戶(hù),進(jìn)行接口請(qǐng)求查詢(xún)。

其中菜單編碼menuCode就是一個(gè)前、后端聯(lián)系的橋梁,細(xì)心的你會(huì)發(fā)現(xiàn),所有后端的接口,與前端對(duì)應(yīng)的都是按鈕操作,所以我們可以以按鈕為基準(zhǔn),實(shí)現(xiàn)前后端雙向控制。

以【角色管理-查詢(xún)】這個(gè)為例,前端可以通過(guò)菜單編碼實(shí)現(xiàn)是否展示這個(gè)查詢(xún)按鈕,后端可以通過(guò)菜單編碼來(lái)判斷,當(dāng)前用戶(hù)是否具備請(qǐng)求接口的權(quán)限。

以后端為例,我們只需編寫(xiě)一個(gè)權(quán)限注解和代理攔截器即可!

  • 編寫(xiě)一個(gè)權(quán)限注解
  1. @Target({ElementType.TYPE, ElementType.METHOD}) 
  2. @Retention(RetentionPolicy.RUNTIME) 
  3. public @interface CheckPermissions { 
  4.  
  5.     String value() default ""
  • 編寫(xiě)一個(gè)代理攔截器,攔截有@CheckPermissions注解的方法
  1. @Aspect 
  2. @Component 
  3. public class CheckPermissionsAspect { 
  4.  
  5.     @Autowired 
  6.     private MenuMapper menuMapper; 
  7.  
  8.     @Pointcut("@annotation(com.company.project.core.annotation.CheckPermissions)"
  9.     public void checkPermissions() {} 
  10.  
  11.     @Before("checkPermissions()"
  12.     public void doBefore(JoinPoint joinPoint) throws Throwable { 
  13.         Long userId = null
  14.         Object[] args = joinPoint.getArgs(); 
  15.         Object parobj = args[0]; 
  16.         //用戶(hù)請(qǐng)求參數(shù)實(shí)體類(lèi)中的用戶(hù)ID 
  17.         if(!Objects.isNull(parobj)){ 
  18.             Class userCla = parobj.getClass(); 
  19.             Field field = userCla.getDeclaredField("userId"); 
  20.             field.setAccessible(true); 
  21.             userId = (Long) field.get(parobj); 
  22.         } 
  23.         if(!Objects.isNull(userId)){ 
  24.             //獲取方法上有CheckPermissions注解的參數(shù) 
  25.             Class clazz = joinPoint.getTarget().getClass(); 
  26.             String methodName = joinPoint.getSignature().getName(); 
  27.             Class[] parameterTypes = ((MethodSignature)joinPoint.getSignature()).getMethod().getParameterTypes(); 
  28.             Method method = clazz.getMethod(methodName, parameterTypes); 
  29.             if(method.getAnnotation(CheckPermissions.class) != null){ 
  30.                 CheckPermissions annotation = method.getAnnotation(CheckPermissions.class); 
  31.                 String menuCode = annotation.value(); 
  32.                 if (StringUtils.isNotBlank(menuCode)) { 
  33.                     //通過(guò)用戶(hù)ID、菜單編碼查詢(xún)是否有關(guān)聯(lián) 
  34.                     int count = menuMapper.selectAuthByUserIdAndMenuCode(userId, menuCode); 
  35.                     if(count == 0){ 
  36.                         throw new CommonException("接口無(wú)訪問(wèn)權(quán)限"); 
  37.                     } 
  38.                 } 
  39.             } 
  40.         } 
  41.     } 
  • 我們以【角色管理-查詢(xún)】為例,先新建一個(gè)請(qǐng)求實(shí)體類(lèi)RoleDto,添加用戶(hù)ID屬性
  1. @Data 
  2. @EqualsAndHashCode(callSuper = false
  3. @Accessors(chain = true
  4. public class RoleDto extends Role { 
  5.  
  6.  //添加用戶(hù)ID 
  7.     private Long userId; 
  • 在需要的接口上,添加@CheckPermissions注解,增加權(quán)限控制
  1. @RestController 
  2. @RequestMapping("/role"
  3. public class RoleController { 
  4.  
  5.     private RoleService roleService; 
  6.  
  7.     @CheckPermissions(value="roleMgr:list"
  8.     @PostMapping(value = "/queryRole"
  9.     public List<Role> queryRole(RoleDto roleDto){ 
  10.         return roleService.list(); 
  11.     } 
  12.  
  13.     @CheckPermissions(value="roleMgr:add"
  14.     @PostMapping(value = "/addRole"
  15.     public void addRole(RoleDto roleDto){ 
  16.         roleService.add(roleDto); 
  17.     } 
  18.  
  19.     @CheckPermissions(value="roleMgr:delete"
  20.     @PostMapping(value = "/deleteRole"
  21.     public void deleteRole(RoleDto roleDto){ 
  22.         roleService.delete(roleDto); 
  23.     } 

依次類(lèi)推,當(dāng)我們想對(duì)某個(gè)接口進(jìn)行權(quán)限控制的時(shí)候,只需要添加一個(gè)注解@CheckPermissions,并填寫(xiě)對(duì)應(yīng)的菜單編碼即可!

四、用戶(hù)權(quán)限

測(cè)試我們先初始化一個(gè)用戶(hù)【張三】,然后給他分配一個(gè)角色【訪客人員】,同時(shí)給這個(gè)角色分配一下2個(gè)菜單權(quán)限【系統(tǒng)配置】、【用戶(hù)管理】,等會(huì)用于權(quán)限測(cè)試。

初始內(nèi)容如下:

 

數(shù)據(jù)初始化完成之后,我們來(lái)啟動(dòng)項(xiàng)目,傳入用戶(hù)【張三】的ID,查詢(xún)用戶(hù)具備的菜單權(quán)限,結(jié)果如下:

 

 

查詢(xún)結(jié)果,用戶(hù)【張三】有兩個(gè)菜單權(quán)限!

接著,我們來(lái)驗(yàn)證一下,用戶(hù)【張三】是否有角色查詢(xún)權(quán)限,請(qǐng)求角色查詢(xún)接口如下:

 

因?yàn)闆](méi)有配置角色查詢(xún)接口,所以無(wú)權(quán)訪問(wèn)!

五、總結(jié)

整片內(nèi)容,只介紹了后端關(guān)鍵的服務(wù)實(shí)現(xiàn)過(guò)程,可能也有遺漏的地方,歡迎網(wǎng)友點(diǎn)評(píng)、吐槽!

 

責(zé)任編輯:武曉燕 來(lái)源: Java極客技術(shù)
相關(guān)推薦

2018-03-23 20:45:23

機(jī)器學(xué)習(xí)NLP文本數(shù)據(jù)

2020-12-08 10:32:15

Python郵件tcp

2021-07-14 09:00:00

JavaFX開(kāi)發(fā)應(yīng)用

2022-02-23 20:53:54

數(shù)據(jù)清洗模型

2011-01-10 14:41:26

2011-05-03 15:59:00

黑盒打印機(jī)

2020-12-07 09:01:58

冪等系統(tǒng)f(f(x)) =f(

2020-07-23 14:39:28

系統(tǒng)權(quán)限設(shè)計(jì)

2022-01-08 20:04:20

攔截系統(tǒng)調(diào)用

2023-04-26 12:46:43

DockerSpringKubernetes

2022-12-07 08:42:35

2022-07-27 08:16:22

搜索引擎Lucene

2022-03-14 14:47:21

HarmonyOS操作系統(tǒng)鴻蒙

2021-06-08 09:49:01

協(xié)程池Golang設(shè)計(jì)

2011-02-22 13:46:27

微軟SQL.NET

2021-12-28 08:38:26

Linux 中斷喚醒系統(tǒng)Linux 系統(tǒng)

2021-02-26 11:54:38

MyBatis 插件接口

2021-12-10 18:19:55

指標(biāo)體系設(shè)計(jì)

2021-12-17 18:21:54

大數(shù)據(jù)流水線設(shè)計(jì)

2017-07-07 11:01:04

Spark性能調(diào)優(yōu)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)