目前java后端主要用的权限认证框架有SpringSecurity、Apache Shiro、Sa-Token这三种,本文主要讲的是SpringSecurity加上前端的自定义权限指令v-permission的简单创建及使用。
仅在后端用SpringSecurity时,分配项目角色的权限时可以发现,给角色分配系统的菜单,不勾选菜单之后角色左侧的菜单路由就不会显示,但是取消勾选按钮后,按钮还是会显示在前端页面中,只是在点击后才会提示“无权限”,那如何使权限范围可以控制到页面上的每一个按钮是否显示?如此精确的范围控制只依赖后端已经难以完成,此时需要前端进行一定的逻辑判断,这里具体讲一下前端做法。
一、创建一个permission.js文件,用于判断用户的权限
/**
* 按钮级权限控制
*/
import { useUserStore } from '@/store/modules/user';
/* 判断数组是否有某些值 */
function arrayHas(array, value) {
if (!value) {
return true;
}
if (!array) {
return false;
}
if (Array.isArray(value)) {
for (let i = 0; i < value.length; i++) {
if (array.indexOf(value[i]) === -1) {
return false;
}
}
return true;
}
return array.indexOf(value) !== -1;
}
/* 判断数组是否有任意值 */
function arrayHasAny(array, value) {
if (!value) {
return true;
}
if (!array) {
return false;
}
if (Array.isArray(value)) {
for (let i = 0; i < value.length; i++) {
if (array.indexOf(value[i]) !== -1) {
return true;
}
}
return false;
}
return array.indexOf(value) !== -1;
}
/**
* 是否有某些角色
* @param value 角色字符或字符数组
*/
export function hasRole(value) {
const userStore = useUserStore();
return arrayHas(userStore?.roles, value);
}
/**
* 是否有任意角色
* @param value 角色字符或字符数组
*/
export function hasAnyRole(value) {
const userStore = useUserStore();
return arrayHasAny(userStore?.roles, value);
}
/**
* 是否有某些权限
* @param value 权限字符或字符数组
*/
export function hasPermission(value) {
const userStore = useUserStore();
return arrayHas(userStore?.authorities, value);
}
/**
* 是否有任意权限
* @param value 权限字符或字符数组
*/
export function hasAnyPermission(value) {
const userStore = useUserStore();
return arrayHasAny(userStore?.authorities, value);
}
export default {
install(app) {
// 添加自定义指令
app.directive('role', {
mounted: (el, binding) => {
if (!hasRole(binding.value)) {
el.parentNode?.removeChild(el);
}
}
});
app.directive('any-role', {
mounted: (el, binding) => {
if (!hasAnyRole(binding.value)) {
el.parentNode?.removeChild(el);
}
}
});
app.directive('permission', {
mounted: (el, binding) => {
if (!hasPermission(binding.value)) {
el.parentNode?.removeChild(el);
}
}
});
app.directive('any-permission', {
mounted: (el, binding) => {
if (!hasAnyPermission(binding.value)) {
el.parentNode?.removeChild(el);
}
}
});
}
};
二、然后在main.js中全局引入这个permission.js。(按需引入,可全局,可局部,这种为全局)
import { createApp } from 'vue';
import App from './App.vue';
import store from './store';
import router from './router';
import permission from './utils/permission';
import i18n from './i18n';
import './styles/index.less';
const app = createApp(App);
app.use(store);
app.use(router);
app.use(permission);
app.use(i18n);
app.mount('#app');
三、使用
<a-button type="primary" class="ele-btn-icon" @click="openAdd()" v-
permission="'sys:caidan:add'">
<template #icon>
<plus-outlined />
</template>
<span >添加</span>
</a-button>
v-permission里放的时你自定义的按钮权限标识符,此时就能完成权限控制到页面上的每一个按钮是否显示。现在可能会有个疑问,前端有了鉴权后端还需要鉴权吗?
需要!
前端的鉴权只是一个辅助功能,对于专业人员这些限制都是可以轻松绕过的,为保证系统安全:无论前端是否进行了权限校验,后端接口都需要对请求再次进行权限校验!