feat: add authorize directive; :star2:
新增:权限验证指令;
| | |
| | | result.data.user = user |
| | | result.data.token = 'Authorization:' + Math.random() |
| | | result.data.expireAt = new Date(new Date().getTime() + 30 * 60 * 1000) |
| | | result.data.permissions = [{id: 'analysis', extra: ['add', 'edit', 'delete']}] |
| | | result.data.roles = [{id: 'admin', extra: ['add', 'edit', 'delete']}] |
| | | result.data.permissions = [{id: 'queryForm', operation: ['add', 'edit', 'delete']}] |
| | | result.data.roles = [{id: 'admin', operation: ['add', 'edit', 'delete']}] |
| | | } |
| | | return result |
| | | }) |
New file |
| | |
| | | /** |
| | | * 获取路由需要的权限 |
| | | * @param permissions |
| | | * @param route |
| | | * @returns {*} |
| | | */ |
| | | const getRoutePermission = (permissions, route) => permissions.find(item => item.id === route.meta.authority.permission) |
| | | /** |
| | | * 获取路由需要的角色 |
| | | * @param roles |
| | | * @param route |
| | | * @returns {*} |
| | | */ |
| | | const getRouteRole = (roles, route) => roles.find(item => item.id === route.meta.authority.role) |
| | | /** |
| | | * 判断是否已为方法注入权限认证 |
| | | * @param method |
| | | * @returns {boolean} |
| | | */ |
| | | const hasInjected = (method) => method.toString().indexOf('//--auth-inject') !== -1 |
| | | |
| | | /** |
| | | * 操作权限校验 |
| | | * @param authConfig |
| | | * @param permission |
| | | * @param role |
| | | * @param permissions |
| | | * @param roles |
| | | * @returns {boolean} |
| | | */ |
| | | const auth = function(authConfig, permission, role, permissions, roles) { |
| | | const {check, type} = authConfig |
| | | if (check && typeof check === 'function') { |
| | | return check(permission, role, permissions, roles) |
| | | } else { |
| | | if (type === 'permission') { |
| | | return permission && permission.operation && permission.operation.indexOf(check) !== -1 |
| | | } else if (type === 'role') { |
| | | return role && role.operation && role.operation.indexOf(check) !== -1 |
| | | } |
| | | } |
| | | return false |
| | | } |
| | | |
| | | /** |
| | | * 阻止的 click 事件监听 |
| | | * @param event |
| | | * @returns {boolean} |
| | | */ |
| | | const preventClick = function (event) { |
| | | event.stopPropagation() |
| | | return false |
| | | } |
| | | |
| | | const checkInject = function (el, binding,vnode) { |
| | | const type = binding.arg |
| | | const check = binding.value |
| | | const instance = vnode.componentInstance |
| | | const $auth = instance.$auth |
| | | if (!$auth || !$auth(check, type)) { |
| | | el.classList.add('disabled') |
| | | el.setAttribute('title', '无此权限') |
| | | el.addEventListener('click', preventClick, true) |
| | | } else { |
| | | el.classList.remove('disabled') |
| | | el.removeAttribute('title') |
| | | el.removeEventListener('click', preventClick, true) |
| | | } |
| | | } |
| | | |
| | | const AuthorityPlugin = { |
| | | install(Vue) { |
| | | Vue.directive('auth', { |
| | | bind(el, binding,vnode) { |
| | | checkInject(el, binding, vnode) |
| | | }, |
| | | update(el, binding,vnode) { |
| | | checkInject(el, binding, vnode) |
| | | } |
| | | }) |
| | | Vue.mixin({ |
| | | beforeCreate() { |
| | | if (this.$options.authorize) { |
| | | const authorize = this.$options.authorize |
| | | Object.keys(authorize).forEach(key => { |
| | | if (this.$options.methods[key]) { |
| | | const method = this.$options.methods[key] |
| | | if (!hasInjected(method)) { |
| | | let authConfig = authorize[key] |
| | | authConfig = (typeof authConfig === 'string') ? {check: authConfig} : authConfig |
| | | const {check, type, onFailure} = authConfig |
| | | this.$options.methods[key] = function () { |
| | | //--auth-inject |
| | | if (this.$auth(check, type)) { |
| | | return method(...arguments) |
| | | } else { |
| | | if (onFailure && typeof onFailure === 'function') { |
| | | this[`$${check}Failure`] = onFailure |
| | | return this[`$${check}Failure`](check) |
| | | } else { |
| | | this.$message.error(`对不起,您没有操作权限:${check}`) |
| | | } |
| | | return 0 |
| | | } |
| | | } |
| | | } |
| | | } |
| | | }) |
| | | } |
| | | }, |
| | | methods: { |
| | | /** |
| | | * 操作权限校验 |
| | | * @param check 需要校验的操作名 |
| | | * @param type 校验类型,通过 permission 校验,还是通过 role 校验。 |
| | | * 如未设置,则自动识别,如匹配到当前路由 permission 则 type = permission,否则 type = role |
| | | * @returns {boolean} 是否校验通过 |
| | | */ |
| | | $auth(check, type) { |
| | | const permissions = this.$store.getters['account/permissions'] |
| | | const roles = this.$store.getters['account/roles'] |
| | | const permission = getRoutePermission(permissions, this.$route) |
| | | const role = getRouteRole(roles, this.$route) |
| | | if (!type) { |
| | | type = permission ? 'permission' : 'role' |
| | | } |
| | | return auth({check, type}, permission, role, permissions, roles) |
| | | } |
| | | } |
| | | }) |
| | | } |
| | | } |
| | | |
| | | export default AuthorityPlugin |
| | |
| | | import VueI18nPlugin from '@/plugins/i18n-extend'; |
| | | import VueI18nPlugin from '@/plugins/i18n-extend' |
| | | import AuthorityPlugin from '@/plugins/authority-plugin' |
| | | |
| | | const Plugins = { |
| | | install: function (Vue) { |
| | | Vue.use(VueI18nPlugin) |
| | | Vue.use(AuthorityPlugin) |
| | | } |
| | | } |
| | | export default Plugins |
| | |
| | | import Vue from 'vue' |
| | | import Router from 'vue-router' |
| | | import {formatAuthority} from '@/utils/routerUtil' |
| | | |
| | | Vue.use(Router) |
| | | |
| | | // 不需要登录拦截的路由配置 |
| | | const loginIgnore = { |
| | | names: ['404'], //根据路由名称匹配 |
| | | names: ['404', '403'], //根据路由名称匹配 |
| | | paths: ['/login'], //根据路由fullPath匹配 |
| | | /** |
| | | * 判断路由是否包含在该配置中 |
| | |
| | | */ |
| | | function initRouter(isAsync) { |
| | | const options = isAsync ? require('./config.async').default : require('./config').default |
| | | formatAuthority(options.routes) |
| | | return new Router(options) |
| | | } |
| | | export {loginIgnore, initRouter} |
| | |
| | | namespaced: true, |
| | | state: { |
| | | user: undefined, |
| | | permissions: [], |
| | | roles: [], |
| | | routesConfig: [] |
| | | permissions: null, |
| | | roles: null, |
| | | routesConfig: null |
| | | }, |
| | | getters: { |
| | | user: state => { |
| | |
| | | return state.user |
| | | }, |
| | | permissions: state => { |
| | | if (!state.permissions || state.permissions.length === 0) { |
| | | if (!state.permissions) { |
| | | try { |
| | | const permissions = localStorage.getItem(process.env.VUE_APP_PERMISSIONS_KEY) |
| | | state.permissions = JSON.parse(permissions) |
| | | state.permissions = state.permissions ? state.permissions : [] |
| | | } catch (e) { |
| | | console.error(e.message) |
| | | } |
| | |
| | | return state.permissions |
| | | }, |
| | | roles: state => { |
| | | if (!state.roles || state.roles.length === 0) { |
| | | if (!state.roles) { |
| | | try { |
| | | const roles = localStorage.getItem(process.env.VUE_APP_ROLES_KEY) |
| | | state.roles = JSON.parse(roles) |
| | | state.roles = state.roles ? state.roles : [] |
| | | } catch (e) { |
| | | console.error(e.message) |
| | | } |
| | |
| | | return state.roles |
| | | }, |
| | | routesConfig: state => { |
| | | if (!state.routesConfig || state.routesConfig.length === 0) { |
| | | if (!state.routesConfig) { |
| | | try { |
| | | const routesConfig = localStorage.getItem(process.env.VUE_APP_ROUTES_KEY) |
| | | state.routesConfig = eval(routesConfig) ? JSON.parse(routesConfig) : state.routesConfig |
| | | state.routesConfig = JSON.parse(routesConfig) |
| | | state.routesConfig = state.routesConfig ? state.routesConfig : [] |
| | | } catch (e) { |
| | | console.error(e.message) |
| | | } |
| | |
| | | border-right: 1px solid rgba(98, 98, 98, 0.2); |
| | | } |
| | | } |
| | | .disabled{ |
| | | cursor: not-allowed; |
| | | opacity: 0.4; |
| | | } |
| | |
| | | if (asyncRoutes) { |
| | | if (routesConfig && routesConfig.length > 0) { |
| | | const routes = parseRoutes(routesConfig, routerMap) |
| | | formatAuthority(routes) |
| | | const finalRoutes = mergeRoutes(router.options.routes, routes) |
| | | router.options = {...router.options, routes: finalRoutes} |
| | | router.matcher = new Router({...router.options, routes:[]}).matcher |
| | |
| | | if (typeof authority === 'object') { |
| | | required = authority.role |
| | | } |
| | | return authority === '*' || (required && roles.findIndex(item => item === required || item.id === required) !== -1) |
| | | return authority === '*' || (required && roles && roles.findIndex(item => item === required || item.id === required) !== -1) |
| | | } |
| | | |
| | | export {parseRoutes, loadRoutes, loginGuard, authorityGuard} |
| | | /** |
| | | * 格式化路由的权限配置 |
| | | * @param routes |
| | | */ |
| | | function formatAuthority(routes) { |
| | | routes.forEach(route => { |
| | | const meta = route.meta |
| | | if (meta) { |
| | | let authority = {} |
| | | if (!meta.authority) { |
| | | authority.permission = '*' |
| | | }else if (typeof meta.authority === 'string') { |
| | | authority.permission = meta.authority |
| | | } else if (typeof meta.authority === 'object') { |
| | | authority = meta.authority |
| | | } else { |
| | | console.log(typeof meta.authority) |
| | | } |
| | | meta.authority = authority |
| | | } else { |
| | | route.meta = { |
| | | authority: {permission: '*'} |
| | | } |
| | | } |
| | | if (route.children) { |
| | | formatAuthority(route.children) |
| | | } |
| | | }) |
| | | } |
| | | |
| | | export {parseRoutes, loadRoutes, loginGuard, authorityGuard, formatAuthority} |