forked from github/dataease
feat: 增加权限设置
This commit is contained in:
parent
a60a243114
commit
a647c66b8a
@ -12,4 +12,6 @@ import java.util.List;
|
||||
public class CurrentUserDto extends SysUserEntity implements Serializable {
|
||||
|
||||
private List<CurrentRoleDto> roles;
|
||||
|
||||
private List<String> permissions;
|
||||
}
|
||||
|
@ -23,6 +23,8 @@ public class DynamicMenuDto implements Serializable {
|
||||
|
||||
private Long id;
|
||||
|
||||
private String permission;
|
||||
|
||||
private List<DynamicMenuDto> children;
|
||||
|
||||
}
|
||||
|
@ -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<CurrentRoleDto> currentRoleDtos = authUserService.roleInfos(user.getUserId());
|
||||
List<String> permissions = authUserService.permissions(user.getUserId());
|
||||
currentUserDto.setRoles(currentRoleDtos);
|
||||
currentUserDto.setPermissions(permissions);
|
||||
return currentUserDto;
|
||||
}
|
||||
|
||||
|
@ -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<String> permissions(Long userId){
|
||||
return authMapper.permissions(userId);
|
||||
List<String> permissions = authMapper.permissions(userId);
|
||||
return permissions.stream().filter(StringUtils::isNotEmpty).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -21,6 +21,7 @@ public class DynamicMenuServiceImpl implements DynamicMenuService {
|
||||
@Override
|
||||
public List<DynamicMenuDto> load(String userId) {
|
||||
SysMenuExample sysMenuExample = new SysMenuExample();
|
||||
sysMenuExample.createCriteria().andTypeLessThanOrEqualTo(1);
|
||||
sysMenuExample.setOrderByClause(" menu_sort ");
|
||||
List<SysMenu> sysMenus = sysMenuMapper.selectByExample(sysMenuExample);
|
||||
List<DynamicMenuDto> 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;
|
||||
}
|
||||
|
||||
|
29
frontend/src/directive/Permission/index.js
Normal file
29
frontend/src/directive/Permission/index.js
Normal file
@ -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)
|
||||
}
|
||||
}
|
8
frontend/src/directive/index.js
Normal file
8
frontend/src/directive/index.js
Normal file
@ -0,0 +1,8 @@
|
||||
import permission from '@/directive/Permission'
|
||||
|
||||
export default {
|
||||
install(Vue) {
|
||||
Vue.directive('permission', permission)
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -10,6 +10,7 @@
|
||||
<span class="operate-button">
|
||||
<ms-table-button
|
||||
v-if="showCreate"
|
||||
v-permission="permission.add"
|
||||
:is-tester-permission="isTesterPermission"
|
||||
icon="el-icon-circle-plus-outline"
|
||||
:content="createTip"
|
||||
@ -67,7 +68,8 @@ export default {
|
||||
default: false
|
||||
},
|
||||
condition: {
|
||||
type: Object
|
||||
type: Object,
|
||||
default: null
|
||||
},
|
||||
createTip: {
|
||||
type: String,
|
||||
@ -76,7 +78,8 @@ export default {
|
||||
}
|
||||
},
|
||||
runTip: {
|
||||
type: String
|
||||
type: String,
|
||||
default: null
|
||||
|
||||
},
|
||||
|
||||
@ -85,10 +88,18 @@ export default {
|
||||
default: false
|
||||
},
|
||||
tip: {
|
||||
String,
|
||||
type: String,
|
||||
default() {
|
||||
return this.$t('commons.search_by_name')
|
||||
}
|
||||
},
|
||||
permission: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {
|
||||
add: []
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<span>
|
||||
<slot name="front" />
|
||||
<ms-table-operator-button :is-tester-permission="isTesterPermission" :tip="tip1" icon="el-icon-edit" @exec="editClick" @click.stop="editClickStop" />
|
||||
<ms-table-operator-button v-permission="permission.edit" :is-tester-permission="isTesterPermission" :tip="tip1" icon="el-icon-edit" @exec="editClick" @click.stop="editClickStop" />
|
||||
<slot name="middle" />
|
||||
<ms-table-operator-button :is-tester-permission="isTesterPermission" :tip="tip2" icon="el-icon-delete" type="danger" @exec="deleteClick" @click.stop="deleteClickStop" />
|
||||
<ms-table-operator-button v-permission="permission.del" :is-tester-permission="isTesterPermission" :tip="tip2" icon="el-icon-delete" type="danger" @exec="deleteClick" @click.stop="deleteClickStop" />
|
||||
<slot name="behind" />
|
||||
</span>
|
||||
|
||||
@ -30,6 +30,16 @@ export default {
|
||||
isTesterPermission: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
permission: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {
|
||||
|
||||
edit: [],
|
||||
del: []
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
})
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
<el-card class="table-card">
|
||||
<template v-slot:header>
|
||||
<ms-table-header
|
||||
:permission="permission"
|
||||
:condition.sync="condition"
|
||||
:create-tip="$t('organization.create')"
|
||||
:title="$t('commons.organization')"
|
||||
@ -45,7 +46,7 @@
|
||||
|
||||
<el-table-column :label="$t('commons.operating')">
|
||||
<template v-slot:default="scope">
|
||||
<ms-table-operator @editClick="edit(scope.row)" @deleteClick="handleDelete(scope.row)" />
|
||||
<ms-table-operator :permission="permission" @editClick="edit(scope.row)" @deleteClick="handleDelete(scope.row)" />
|
||||
</template>
|
||||
</el-table-column> -->
|
||||
</el-table>
|
||||
@ -167,6 +168,11 @@ export default {
|
||||
description: [
|
||||
{ max: 50, message: this.$t('commons.input_limit', [0, 50]), trigger: 'blur' }
|
||||
]
|
||||
},
|
||||
permission: {
|
||||
add: ['dept:add'],
|
||||
edit: ['dept:edit'],
|
||||
del: ['dept:del']
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
<el-card class="table-card">
|
||||
<template v-slot:header>
|
||||
<ms-table-header
|
||||
:permission="permission"
|
||||
:condition.sync="condition"
|
||||
:create-tip="$t('menu.create')"
|
||||
:title="$t('commons.menu')"
|
||||
@ -58,9 +59,9 @@
|
||||
|
||||
<el-table-column :label="$t('commons.operating')">
|
||||
<template v-slot:default="scope">
|
||||
<ms-table-operator @editClick="edit(scope.row)" @deleteClick="handleDelete(scope.row)" />
|
||||
<ms-table-operator :permission="permission" @editClick="edit(scope.row)" @deleteClick="handleDelete(scope.row)" />
|
||||
</template>
|
||||
</el-table-column> -->
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
</el-card>
|
||||
@ -210,6 +211,11 @@ export default {
|
||||
description: [
|
||||
{ max: 50, message: this.$t('commons.input_limit', [0, 50]), trigger: 'blur' }
|
||||
]
|
||||
},
|
||||
permission: {
|
||||
add: ['menu:add'],
|
||||
edit: ['menu:edit'],
|
||||
del: ['menu:del']
|
||||
}
|
||||
|
||||
}
|
||||
@ -220,6 +226,7 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
create() {
|
||||
this.form = Object.assign({}, this.defaultForm)
|
||||
this.dialogVisible = true
|
||||
this.formType = 'add'
|
||||
listenGoBack(this.closeFunc)
|
||||
|
@ -4,7 +4,7 @@
|
||||
<el-aside width="70%" style="border: 1px solid #eee">
|
||||
<el-card class="table-card">
|
||||
<template v-slot:header>
|
||||
<ms-table-header :condition.sync="condition" :create-tip="$t('role.add')" :title="$t('commons.role')" @search="search" @create="create" />
|
||||
<ms-table-header :permission="permission" :condition.sync="condition" :create-tip="$t('role.add')" :title="$t('commons.role')" @search="search" @create="create" />
|
||||
</template>
|
||||
<el-table border highlight-current-row class="adjust-table" :data="tableData" style="width: 100%;" @row-click="rowClick">
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('commons.operating')">
|
||||
<template v-slot:default="scope">
|
||||
<ms-table-operator @editClick="edit(scope.row)" @deleteClick="handleDelete(scope.row)" />
|
||||
<ms-table-operator :permission="permission" @editClick="edit(scope.row)" @deleteClick="handleDelete(scope.row)" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@ -121,7 +121,12 @@ export default {
|
||||
{ required: true, message: '请输入名称', trigger: 'blur' }
|
||||
]
|
||||
},
|
||||
currentRow: null
|
||||
currentRow: null,
|
||||
permission: {
|
||||
add: ['role:add'],
|
||||
edit: ['role:edit'],
|
||||
del: ['role:del']
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
@ -4,6 +4,7 @@
|
||||
<el-card class="table-card">
|
||||
<template v-slot:header>
|
||||
<ms-table-header
|
||||
:permission="permission"
|
||||
:condition.sync="condition"
|
||||
:create-tip="$t('user.create')"
|
||||
:title="$t('commons.user')"
|
||||
@ -38,7 +39,7 @@
|
||||
<!-- <el-table-column prop="source" :label="$t('user.source')"/> -->
|
||||
<el-table-column :label="$t('commons.operating')" min-width="120px">
|
||||
<template v-slot:default="scope">
|
||||
<ms-table-operator @editClick="edit(scope.row)" @deleteClick="del(scope.row)">
|
||||
<ms-table-operator :permission="permission" @editClick="edit(scope.row)" @deleteClick="del(scope.row)">
|
||||
<template v-slot:behind>
|
||||
<ms-table-operator-button
|
||||
v-if="scope.row.isLocalUser"
|
||||
@ -274,7 +275,12 @@ export default {
|
||||
roles: [],
|
||||
roleDatas: [],
|
||||
userRoles: [],
|
||||
formType: 'add'
|
||||
formType: 'add',
|
||||
permission: {
|
||||
add: ['user:add'],
|
||||
edit: ['user:edit'],
|
||||
del: ['user:del']
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -18,7 +18,7 @@
|
||||
{{ scope.row.title }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="Author" width="110" align="center">
|
||||
<el-table-column v-permission="['menu:del']" label="Author" width="110" align="center">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.author }}</span>
|
||||
</template>
|
||||
|
Loading…
Reference in New Issue
Block a user