后端 springboot + 拦截器 + 注解 实现自定义权限验证
前端 vue 自定义指令 v-has
思路
ElementUI , 权限设计思路也是参考了 vueAdmin 的动态路由的设计.
后端负责了接口的安全性,而前端之所以要做权限处理,最主要的目的就是隐藏掉不具有权限的菜单(路由)和按钮.
前端对于按钮级别权限的控制方法,根据后端返回的权限数据来实现不同权限的用户展示不同的操作按钮。
基于 RBAC新解 .
通常我们的权限设计都是 用户–角色–权限 ,其中角色是我们写代码的人没法控制的,它可以有多条权限,每个用户又可以设计为拥有多个角色.因此如果从角色着手进行权限验证,系统都必须根据用户的配置动起来,非常复杂.
后台设计的关键点就在于: 后台接口只验证权限,不看角色.
角色的作用其实只是用来管理分配权限的,真正的验证只验证权限 ,而不去管你是否是哪种角色
一 数据库
1.用户跟角色关联
2.角色跟菜单关联
3.菜单跟菜单下的按钮关联
4.后端返回每个菜单下的按钮,前端通过自定义事件,在每个按钮上加上相应的事件
数据库表设计
数据库表为5个分别是: 用户表、角色表、权限表、用户角色中间表、角色权限中间表
角色菜单
二 后端
后端 springboot + 拦截器 + 注解 实现自定义权限验证
定义权限的注解 @RequiredPermission
实现一个 @RequirePermission 注解,有一个名称为value的属性,若只设置value属性可以省略掉“value=”部分
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequiredPermission {
String value() default "";
}
拦截器(只验证权限)
指定类型的注释存在于此元素上,后台接口只验证权限
@Configuration
public class WebPageHandlerInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {
Method method = handlerMethod.getMethod();
// if(method.isAnnotationPresent(RequirePermission.class)){ return true; }
//check permission
if(method.isAnnotationPresent(RequiredPermission.class)){
RequiredPermission perm = method.getAnnotation(RequiredPermission.class);
String btnCode = perm.value();
boolean hasPer = user.btnPermissions.contains(btnCode);
logger.info("权限认证:{}, user permission:{}", hasPer, perm.value());
if(!hasPer){
response.getWriter().print("无权限"));
return false;
}
}
业务代码—引入注解
在查询搜索接口中,引入注解,如查询列表数据
@RequiredPermission("user:search")
@RequestMapping("/queryUserList")
public Object queryUserList(@CurrentUser SysUser cu, String userId, String userAccount){
return Rsp.end(Result.Err.SUCCESS);
}
三 前端 VUE 自定义指令 v-has
页面查询按钮 v-has
v-has 中 ‘user:search’ 会显示和隐藏该权限按钮
<el-button type="primary" v-has="'user:search'" @click="handleSearch()">查询</el-button>
main.js
import * as has from '@/assets/js/btnPermission.js'
Vue.use(has)
Vue.prototype.$has = has
自定义 permissions.js 文件
文件位置 assets/js/btnPermission.js
//登录接口返回保存按钮权限数组
localStorage.btnPermissions = rsp.data.btnPermissions;
import Vue from 'vue'
const has = Vue.directive('has', {
//获取按钮权限
inserted: function (el, binding, vnode) {
//let permissions = ['add', 'edit', 'cancel', 'confirm', 'delete', 'detail', 'search', 'download', 'back'];
//permissions = vnode.context.$route.meta.btnPermissions;
//
let permissions = localStorage.btnPermissions;
if (!Vue.prototype.$_has(permissions, binding.value)) {
if(el.parentNode){
el.parentNode.removeChild(el);
}
}
}
});
//权限检查方法
Vue.prototype.$_has = function(permissions, value) {
let isExist = false;
if (permissions == null || permissions == undefined) {
return false
}
if (permissions.indexOf(value) > -1) {
isExist = true
}
return isExist
}
关于 vue 指令中el 的 parentNode 为空的问题
https://www.cnblogs.com/chenmz1995/p/11453228.html
参考资料
vue+springboot后台实现页面按钮权限
https://www.cnblogs.com/xiaokangk/p/11511721.html
前端控制权限隐藏按钮 vue自定义指令v-has
https://blog.csdn.net/weixin_44914782/article/details/109239798
(文章)Springboot如何做一个简单的权限管理
https://www.zhihu.com/question/363704837/answer/958505035