spring-boot-plus V1.4.0發布 集成用戶角色許可權部門管理

  • 2019 年 11 月 5 日
  • 筆記

RBAC用戶角色許可權

用戶角色許可權部門管理核心介面介紹

Shiro許可權配置

資料庫模型圖

spring-boot-plus資料庫模型圖

獲取驗證碼

  • 可配置是否啟用驗證碼
  • 默認未啟用
  • 如已啟用驗證碼校驗,登陸時,需傳入verifyToken和code

驗證碼演示

spring-boot-plus:    # 是否啟用ansi控制台輸出有顏色的字體    enable-ansi: true    # 是否啟用驗證碼    enable-verify-code: true

enable-verify-code 設置為 true 啟用驗證碼驗證

兩種方式獲取驗證碼

驗證碼後台保存在Redis中,過期時間默認為5分鐘

驗證碼Swagger

方式一:

輸出圖片流到瀏覽器,驗證碼token輸出到響應頭

http://localhost:8888/verificationCode/getImage

驗證碼圖片

Response Headers  HTTP/1.1 200  verifyToken: 6515b4b798ce49e68b1e40f98ff8eb19
方式二:

獲取Base64編碼圖片和驗證碼token

http://localhost:8888/verificationCode/getBase64Image
{    "code": 200,    "msg": "操作成功",    "success": true,    "data": {      "image": "data:image/png;base64,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",      "verifyToken": "42ba8abde7bc47b2b1397b4d6676956a"    },    "time": "2019-11-01 22:40:37"  }

系統用戶登陸

驗證碼Swagger

  • POST請求,Content-Type: application/json
http://127.0.0.1:8888/login
  • 請求參數
{    "code": "驗證碼",    "password": "123456",    "username": "admin",    "verifyToken": "驗證碼token"  }

注意

  • 如果沒有啟用驗證碼登陸,則只需傳入usernamepassword
  • 前端應將密碼加密後進行傳輸

登陸成功

  • 返回登陸用戶資訊:部門/角色/許可權
  • 返回用戶token
{    "code": 200,    "msg": "登陸成功",    "success": true,    "data": {      "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJ3ZWIiLCJpc3MiOiJzcHJpbmctYm9vdC1wbHVzIiwiZXhwIjoxNTcyNjIzMDE5LCJpYXQiOjE1NzI2MTk0MTksImp0aSI6IjdlZmVlM2UwMjc2MTRiYTc5M2I2YmYwZmE4NTgzYmUwIiwidXNlcm5hbWUiOiJhZG1pbiJ9.O3w7CNRqw_Miwp8MDzPND6w490c9Q7yFlKpFJK9ubSU",      "loginSysUserVo": {        "id": "1",        "username": "admin",        "nickname": "管理員",        "gender": 1,        "state": 1,        "departmentId": "1",        "departmentName": "管理部",        "roleId": "1",        "roleName": "管理員",        "roleCode": "admin",        "permissionCodes": [          "sys:permission:codes",          "system:management",          "sys:department:update",          "sys:department:page",          "sys:role:management",          "sys:permission:add",          "sys:user:add",          "sys:role:page",          "sys:permission:page",          "sys:department:delete",          "sys:permission:management",          "sys:user:delete",          "sys:department:management",          "sys:user:page",          "sys:user:update",          "sys:user:update:password",          "sys:user:update:head",          "sys:role:add",          "sys:permission:menu:tree",          "sys:department:info",          "sys:permission:all:menu:list",          "sys:permission:info",          "sys:role:info",          "sys:permission:all:menu:tree",          "sys:permission:update",          "sys:permission:menu:list",          "sys:role:update",          "sys:user:info",          "sys:user:management",          "sys:role:delete",          "sys:permission:delete"        ]      }    },    "time": "2019-11-01 22:43:39"  }
  • token默認失效時間為1個小時
  • 設置JWT Token失效時間
  ############################ JWT start #############################    jwt:      # 默認過期時間1小時,單位:秒      expire-second: 3600
  • 後台使用Redis快取登陸用戶資訊
  • redis key
login:user:admin
其它需要授權訪問的介面,請求頭需攜帶token

部門樹形列表

  • 部門可以設置為N級,後台使用遞歸將部門列錶轉換為樹形列表

驗證碼Swagger

  • SysDepartmentServiceImpl
    @Override      public List<SysDepartmentTreeVo> getAllDepartmentTree() {          List<SysDepartment> sysDepartmentList = getAllDepartmentList();          if (CollectionUtils.isEmpty(sysDepartmentList)) {              throw new IllegalArgumentException("SysDepartment列表不能為空");          }          List<SysDepartmentTreeVo> list = SysDepartmentConvert.INSTANCE.listToTreeVoList(sysDepartmentList);          List<SysDepartmentTreeVo> treeVos = new ArrayList<>();          for (SysDepartmentTreeVo treeVo : list) {              if (treeVo.getParentId() == null) {                  treeVos.add(findChildren(treeVo, list));              }          }          return treeVos;      }        /**       * 遞歸獲取樹形結果列表       *       * @param tree       * @param list       * @return       */      public SysDepartmentTreeVo findChildren(SysDepartmentTreeVo tree, List<SysDepartmentTreeVo> list) {          for (SysDepartmentTreeVo vo : list) {              if (tree.getId().equals(vo.getParentId())) {                  if (tree.getChildren() == null) {                      tree.setChildren(new ArrayList<>());                  }                  tree.getChildren().add(findChildren(vo, list));              }          }          return tree;      }
  • 前端JSON結構
http://127.0.0.1:8888/sysDepartment/getAllDepartmentTree

角色管理

驗證碼Swagger

設置角色許可權

  • 核心程式碼,刪除角色許可權,新增角色許可權
  • 求集合的差集
  • SysRolePermissionServiceImpl
    @Transactional(rollbackFor = Exception.class)      @Override      public boolean updateSysRole(UpdateSysRoleParam updateSysRoleParam) throws Exception {          Long roleId = updateSysRoleParam.getId();          List<Long> permissionIds = updateSysRoleParam.getPermissionIds();          // 校驗角色是否存在          SysRole sysRole = getById(roleId);          if (sysRole == null) {              throw new BusinessException("該角色不存在");          }          // 校驗許可權列表是否存在          if (!sysPermissionService.isExistsByPermissionIds(permissionIds)) {              throw new BusinessException("許可權列表id匹配失敗");          }            // 修改角色          sysRole.setName(updateSysRoleParam.getName())                  .setType(updateSysRoleParam.getType())                  .setRemark(updateSysRoleParam.getRemark())                  .setState(updateSysRoleParam.getState())                  .setUpdateTime(new Date());          boolean updateResult = updateById(sysRole);          if (!updateResult) {              throw new DaoException("修改系統角色失敗");          }            // 獲取之前的許可權id集合          List<Long> beforeList = sysRolePermissionService.getPermissionIdsByRoleId(roleId);          // 差集計算          // before:1,2,3,4,5,6          // after: 1,2,3,4,7,8          // 刪除5,6 新增7,8          // 此處真實刪除,去掉deleted欄位的@TableLogic註解          Set<Long> beforeSet = new HashSet<>(beforeList);          Set<Long> afterSet = new HashSet<>(permissionIds);          SetUtils.SetView deleteSet = SetUtils.difference(beforeSet, afterSet);          SetUtils.SetView addSet = SetUtils.difference(afterSet, beforeSet);          log.debug("deleteSet = " + deleteSet);          log.debug("addSet = " + addSet);            // 刪除許可權關聯          UpdateWrapper updateWrapper = new UpdateWrapper();          updateWrapper.eq("role_id",roleId);          updateWrapper.in("permission_id",deleteSet);          boolean deleteResult = sysRolePermissionService.remove(updateWrapper);          if (!deleteResult) {              throw new DaoException("刪除角色許可權關係失敗");          }          // 新增許可權關聯          boolean addResult = sysRolePermissionService.saveSysRolePermissionBatch(roleId, addSet);          if (!addResult) {              throw new DaoException("新增角色許可權關係失敗");          }          return true;      }

許可權管理

驗證碼Swagger

許可權樹形列表

  • 用戶設置角色許可權時,選擇許可權菜單
  • 許可權分為菜單和功能許可權
  • 後台獲取三層許可權樹
    @Override      public List<SysPermissionTreeVo> getAllMenuTree() throws Exception {          List<SysPermission> list = getAllMenuList();          // 轉換成樹形菜單          List<SysPermissionTreeVo> treeVos = convertSysPermissionTreeVoList(list);          return treeVos;      }        @Override      public List<SysPermissionTreeVo> convertSysPermissionTreeVoList(List<SysPermission> list) {          if (CollectionUtils.isEmpty(list)) {              throw new IllegalArgumentException("SysPermission列表不能為空");          }          // 按level分組獲取map          Map<Integer, List<SysPermission>> map = list.stream().collect(Collectors.groupingBy(SysPermission::getLevel));          List<SysPermissionTreeVo> treeVos = new ArrayList<>();          // 循環獲取三級菜單樹形集合          for (SysPermission one : map.get(LevelEnum.ONE.getKey())) {              SysPermissionTreeVo oneVo = SysPermissionConvert.INSTANCE.permissionToTreeVo(one);              Long oneParentId = oneVo.getParentId();              if (oneParentId == null || oneParentId == 0) {                  treeVos.add(oneVo);              }              List<SysPermission> twoList = map.get(LevelEnum.TWO.getKey());              if (CollectionUtils.isNotEmpty(twoList)) {                  for (SysPermission two : twoList) {                      SysPermissionTreeVo twoVo = SysPermissionConvert.INSTANCE.permissionToTreeVo(two);                      if (two.getParentId().equals(one.getId())) {                          oneVo.getChildren().add(twoVo);                      }                      List<SysPermission> threeList = map.get(LevelEnum.THREE.getKey());                      if (CollectionUtils.isNotEmpty(threeList)) {                          for (SysPermission three : threeList) {                              if (three.getParentId().equals(two.getId())) {                                  SysPermissionTreeVo threeVo = SysPermissionConvert.INSTANCE.permissionToTreeVo(three);                                  twoVo.getChildren().add(threeVo);                              }                          }                      }                  }              }            }          return treeVos;      }
  • 前端JSON格式
http://127.0.0.1:8888/sysPermission/getAllMenuTree

許可權編碼列表

返回當前用戶所有的許可權編碼,方便前端展示導航菜單和功能按鈕

http://127.0.0.1:8888/sysPermission/getPermissionCodesByUserId/1
{    "code": 200,    "msg": "操作成功",    "success": true,    "data": [      "system:management",      "system:management",      "sys:user:management",      "sys:user:management",      "sys:role:management",      "sys:permission:management",      "sys:department:management",      "sys:user:add",      "sys:user:add",      "sys:user:update",      "sys:user:update",      "sys:user:delete",      "sys:user:delete",      "sys:user:info",      "sys:user:info",      "sys:user:page",      "sys:user:page",      "sys:user:update:password",      "sys:user:update:head",      "sys:role:add",      "sys:role:update",      "sys:role:delete",      "sys:role:info",      "sys:role:page",      "sys:permission:add",      "sys:permission:update",      "sys:permission:delete",      "sys:permission:info",      "sys:permission:page",      "sys:permission:all:menu:list",      "sys:permission:all:menu:tree",      "sys:permission:menu:list",      "sys:permission:menu:tree",      "sys:permission:codes",      "sys:department:update",      "sys:department:delete",      "sys:department:info",      "sys:department:page"    ],    "time": "2019-11-02 00:32:17"  }

注意

  • 使用Shiro註解@RequiresPermissions進行controller方法許可權過濾
@RequiresPermissions("sys:department:add")
  • 生成程式碼時,可配置生成RequiresPermissions註解
        // 是否生成Shiro RequiresPermissions註解          codeGenerator.setRequiresPermissions(true);
  • 生成或新增的controller方法,需要進行許可權管理,需要到sys_permission表新增許可權編碼記錄,並給相應角色賦予許可權