From a647c66b8a8655c468befc67c905a02dc45ee7ef Mon Sep 17 00:00:00 2001 From: fit2cloud-chenyw Date: Fri, 5 Mar 2021 16:07:44 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E6=9D=83=E9=99=90?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dataease/auth/api/dto/CurrentUserDto.java | 2 ++ .../dataease/auth/api/dto/DynamicMenuDto.java | 2 ++ .../io/dataease/auth/server/AuthServer.java | 3 +- .../service/impl/AuthUserServiceImpl.java | 5 +++- .../service/impl/DynamicMenuServiceImpl.java | 2 ++ frontend/src/directive/Permission/index.js | 29 +++++++++++++++++++ frontend/src/directive/index.js | 8 +++++ frontend/src/main.js | 5 +++- .../common/components/MsTableHeader.vue | 17 +++++++++-- .../common/components/MsTableOperator.vue | 14 +++++++-- frontend/src/permission.js | 27 ++++++++++++++++- frontend/src/store/getters.js | 3 +- frontend/src/store/modules/permission.js | 2 +- frontend/src/store/modules/user.js | 12 ++++++-- frontend/src/utils/validate.js | 2 +- frontend/src/views/system/dept/index.vue | 8 ++++- frontend/src/views/system/menu/index.vue | 11 +++++-- frontend/src/views/system/role/index.vue | 11 +++++-- frontend/src/views/system/user/index.vue | 10 +++++-- frontend/src/views/table/index.vue | 2 +- 20 files changed, 151 insertions(+), 24 deletions(-) create mode 100644 frontend/src/directive/Permission/index.js create mode 100644 frontend/src/directive/index.js diff --git a/backend/src/main/java/io/dataease/auth/api/dto/CurrentUserDto.java b/backend/src/main/java/io/dataease/auth/api/dto/CurrentUserDto.java index 49e0826aa8..ab279d815d 100644 --- a/backend/src/main/java/io/dataease/auth/api/dto/CurrentUserDto.java +++ b/backend/src/main/java/io/dataease/auth/api/dto/CurrentUserDto.java @@ -12,4 +12,6 @@ import java.util.List; public class CurrentUserDto extends SysUserEntity implements Serializable { private List roles; + + private List permissions; } diff --git a/backend/src/main/java/io/dataease/auth/api/dto/DynamicMenuDto.java b/backend/src/main/java/io/dataease/auth/api/dto/DynamicMenuDto.java index 5d0504f7d6..d79a6e6bbd 100644 --- a/backend/src/main/java/io/dataease/auth/api/dto/DynamicMenuDto.java +++ b/backend/src/main/java/io/dataease/auth/api/dto/DynamicMenuDto.java @@ -23,6 +23,8 @@ public class DynamicMenuDto implements Serializable { private Long id; + private String permission; + private List children; } diff --git a/backend/src/main/java/io/dataease/auth/server/AuthServer.java b/backend/src/main/java/io/dataease/auth/server/AuthServer.java index 9d990ed342..11453e1886 100644 --- a/backend/src/main/java/io/dataease/auth/server/AuthServer.java +++ b/backend/src/main/java/io/dataease/auth/server/AuthServer.java @@ -14,7 +14,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; -import javax.servlet.http.HttpServletResponse; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -59,7 +58,9 @@ public class AuthServer implements AuthApi { SysUserEntity user = authUserService.getUser(username); CurrentUserDto currentUserDto = BeanUtils.copyBean(new CurrentUserDto(), user); List currentRoleDtos = authUserService.roleInfos(user.getUserId()); + List permissions = authUserService.permissions(user.getUserId()); currentUserDto.setRoles(currentRoleDtos); + currentUserDto.setPermissions(permissions); return currentUserDto; } diff --git a/backend/src/main/java/io/dataease/auth/service/impl/AuthUserServiceImpl.java b/backend/src/main/java/io/dataease/auth/service/impl/AuthUserServiceImpl.java index 4a77044bda..314be618c6 100644 --- a/backend/src/main/java/io/dataease/auth/service/impl/AuthUserServiceImpl.java +++ b/backend/src/main/java/io/dataease/auth/service/impl/AuthUserServiceImpl.java @@ -4,11 +4,13 @@ import io.dataease.auth.api.dto.CurrentRoleDto; import io.dataease.auth.entity.SysUserEntity; import io.dataease.base.mapper.ext.AuthMapper; import io.dataease.auth.service.AuthUserService; +import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; @Service public class AuthUserServiceImpl implements AuthUserService { @@ -27,7 +29,8 @@ public class AuthUserServiceImpl implements AuthUserService { } @Override public List permissions(Long userId){ - return authMapper.permissions(userId); + List permissions = authMapper.permissions(userId); + return permissions.stream().filter(StringUtils::isNotEmpty).collect(Collectors.toList()); } @Override diff --git a/backend/src/main/java/io/dataease/auth/service/impl/DynamicMenuServiceImpl.java b/backend/src/main/java/io/dataease/auth/service/impl/DynamicMenuServiceImpl.java index aed036b9bb..1d256f478b 100644 --- a/backend/src/main/java/io/dataease/auth/service/impl/DynamicMenuServiceImpl.java +++ b/backend/src/main/java/io/dataease/auth/service/impl/DynamicMenuServiceImpl.java @@ -21,6 +21,7 @@ public class DynamicMenuServiceImpl implements DynamicMenuService { @Override public List load(String userId) { SysMenuExample sysMenuExample = new SysMenuExample(); + sysMenuExample.createCriteria().andTypeLessThanOrEqualTo(1); sysMenuExample.setOrderByClause(" menu_sort "); List sysMenus = sysMenuMapper.selectByExample(sysMenuExample); List dynamicMenuDtos = sysMenus.stream().map(this::convert).collect(Collectors.toList()); @@ -40,6 +41,7 @@ public class DynamicMenuServiceImpl implements DynamicMenuService { menuMeta.setTitle(sysMenu.getTitle()); menuMeta.setIcon(sysMenu.getIcon()); dynamicMenuDto.setMeta(menuMeta); + dynamicMenuDto.setPermission(sysMenu.getPermission()); return dynamicMenuDto; } diff --git a/frontend/src/directive/Permission/index.js b/frontend/src/directive/Permission/index.js new file mode 100644 index 0000000000..70a6230c06 --- /dev/null +++ b/frontend/src/directive/Permission/index.js @@ -0,0 +1,29 @@ +import store from '@/store' + +function checkPermission(el, binding) { + const { value } = binding + // 我们是基于资源授鉴权 不用角色 因为后期可能有对部门授权 对 人员授权 + const permissions = store.getters && store.getters.permissions + if (value && value instanceof Array) { + const needPermissions = value + // 满足指令中的每个权限才可放行 而不是 满足任意一个即可 + const hasPermission = needPermissions.every(needP => { + const result = permissions.includes(needP) + return result + }) + if (!hasPermission) { + el.parentNode && el.parentNode.removeChild(el) + } + } else { + throw new Error(`使用方式: v-permission="['user:read']"`) + } +} + +export default { + inserted(el, binding) { + checkPermission(el, binding) + }, + update(el, binding) { + checkPermission(el, binding) + } +} diff --git a/frontend/src/directive/index.js b/frontend/src/directive/index.js new file mode 100644 index 0000000000..4692271b69 --- /dev/null +++ b/frontend/src/directive/index.js @@ -0,0 +1,8 @@ +import permission from '@/directive/Permission' + +export default { + install(Vue) { + Vue.directive('permission', permission) + } +} + diff --git a/frontend/src/main.js b/frontend/src/main.js index 08eca31d41..f922177b26 100644 --- a/frontend/src/main.js +++ b/frontend/src/main.js @@ -14,11 +14,12 @@ import router from './router' import '@/icons' // icon import '@/permission' // permission control - import api from '@/api/index.js' import filter from '@/filter/filter' import message from '@/metersphere/common/js/message' import { left2RightDrag, bottom2TopDrag, right2LeftDrag } from '@/metersphere/common/js/directive' +import directives from './directive' + Vue.prototype.$api = api import * as echarts from 'echarts' @@ -50,11 +51,13 @@ Vue.use(Fit2CloudUI, { }) Vue.use(filter) Vue.use(message) +Vue.use(directives) Vue.config.productionTip = false // 支持左右拖拽 Vue.directive('left-to-right-drag', left2RightDrag) Vue.directive('right-to-left-drag', right2LeftDrag) Vue.directive('bottom-to-top-drag', bottom2TopDrag) + new Vue({ el: '#app', router, diff --git a/frontend/src/metersphere/common/components/MsTableHeader.vue b/frontend/src/metersphere/common/components/MsTableHeader.vue index 726fc6cef3..32ae664023 100644 --- a/frontend/src/metersphere/common/components/MsTableHeader.vue +++ b/frontend/src/metersphere/common/components/MsTableHeader.vue @@ -10,6 +10,7 @@ - + - + @@ -30,6 +30,16 @@ export default { isTesterPermission: { type: Boolean, default: false + }, + permission: { + type: Object, + default() { + return { + + edit: [], + del: [] + } + } } }, methods: { diff --git a/frontend/src/permission.js b/frontend/src/permission.js index 6bb2d162ea..00b155fa3b 100644 --- a/frontend/src/permission.js +++ b/frontend/src/permission.js @@ -66,7 +66,8 @@ router.beforeEach(async(to, from, next) => { }) export const loadMenus = (next, to) => { buildMenus().then(res => { - const asyncRouter = filterAsyncRouter(res.data) + const filterDatas = filterRouter(res.data) + const asyncRouter = filterAsyncRouter(filterDatas) asyncRouter.push({ path: '*', redirect: '/404', hidden: true }) store.dispatch('permission/GenerateRoutes', asyncRouter).then(() => { // 存储路由 router.addRoutes(asyncRouter) @@ -74,6 +75,30 @@ export const loadMenus = (next, to) => { }) }) } + +// 根据权限过滤菜单 +const filterRouter = routers => { + const user_permissions = store.getters.permissions + if (!user_permissions || user_permissions.length === 0) { + return routers + } + const tempResults = routers.filter(router => hasPermission(router, user_permissions)) + // 如果是一级菜单(目录) 没有字菜单 那就移除 + return tempResults.filter(item => item.children && item.children.length) +} +const hasPermission = (router, user_permissions) => { + // 菜单要求权限 但是当前用户权限没有包含菜单权限 + if (router.permission && !user_permissions.includes(router.permission)) { + return false + } + // 如果有字菜单 则 判断是否满足 ‘任意一个子菜单有权限’ + if (router.children && router.children.length) { + const permissionChilds = router.children.filter(item => hasPermission(item, user_permissions)) + router.children = permissionChilds + return router.children.length > 0 + } + return true +} router.afterEach(() => { // finish progress bar NProgress.done() diff --git a/frontend/src/store/getters.js b/frontend/src/store/getters.js index 4f1af6f479..38282751a2 100644 --- a/frontend/src/store/getters.js +++ b/frontend/src/store/getters.js @@ -16,6 +16,7 @@ const getters = { sceneData: state => state.dataset.sceneData, table: state => state.dataset.table, loadingMap: state => state.request.loadingMap, - currentPath: state => state.permission.currentPath + currentPath: state => state.permission.currentPath, + permissions: state => state.user.permissions } export default getters diff --git a/frontend/src/store/modules/permission.js b/frontend/src/store/modules/permission.js index 1477744af1..a21c7a5fd1 100644 --- a/frontend/src/store/modules/permission.js +++ b/frontend/src/store/modules/permission.js @@ -47,7 +47,7 @@ export const filterAsyncRouter = (routers) => { // 遍历后台传来的路由 }).map(router => { router.hasOwnProperty('id') && delete router.id router.hasOwnProperty('pid') && delete router.pid - router.hasOwnProperty('children') && !router['children'] && delete router.children + router.hasOwnProperty('children') && (!router['children'] || !router['children'].length) && delete router.children router.hasOwnProperty('redirect') && !router['redirect'] && delete router.redirect return router }) diff --git a/frontend/src/store/modules/user.js b/frontend/src/store/modules/user.js index c16f94a5a7..ee02cef92a 100644 --- a/frontend/src/store/modules/user.js +++ b/frontend/src/store/modules/user.js @@ -10,7 +10,9 @@ const getDefaultState = () => { roles: [], avatar: '', // 第一次加载菜单时用到 - loadMenus: false + loadMenus: false, + // 当前用户拥有哪些资源权限 + permissions: [] } } @@ -37,6 +39,9 @@ const mutations = { }, SET_LOAD_MENUS: (state, loadMenus) => { state.loadMenus = loadMenus + }, + SET_PERMISSIONS: (state, permissions) => { + state.permissions = permissions } } @@ -68,12 +73,13 @@ const actions = { const currentUser = data commit('SET_USER', currentUser) - const roles = data.roles + const { roles, nickName, permissions } = data commit('SET_ROLES', roles) - const { nickName } = data commit('SET_NAME', nickName) // commit('SET_AVATAR', avatar) + + commit('SET_PERMISSIONS', permissions) resolve(data) }).catch(error => { reject(error) diff --git a/frontend/src/utils/validate.js b/frontend/src/utils/validate.js index 8d962ad4a2..1e5024e641 100644 --- a/frontend/src/utils/validate.js +++ b/frontend/src/utils/validate.js @@ -15,6 +15,6 @@ export function isExternal(path) { * @returns {Boolean} */ export function validUsername(str) { - const valid_map = ['admin', 'editor'] + const valid_map = ['admin', 'cyw'] return valid_map.indexOf(str.trim()) >= 0 } diff --git a/frontend/src/views/system/dept/index.vue b/frontend/src/views/system/dept/index.vue index 0f61519eeb..7a7e9a0b19 100644 --- a/frontend/src/views/system/dept/index.vue +++ b/frontend/src/views/system/dept/index.vue @@ -4,6 +4,7 @@