(五)Vue实用框架-Ruoyi(权限控制和页面渲染)
路由的组成
前端token获取那一步中有一块内容,只是简单提了一下,但其实实际涉及到的内容很多:
用户信息的获取
第一步的GetInfo后端接口不讲了,因为接口都比较简单,就根据获取得到的数据展开下:
前端权限控制粒度
依旧挑重点讲,user对象的无非就是包含了 部门dept 和 角色roles 信息,但有个 permissions : 就拿 system:user:resetPwd 来说,system代表一级路由的关键词(也是路由地址),user是二级路由的关键词,resetPwd是对这个页面中某些操作的描述关键词,具体看下图:
这套权限控制前端有按钮粒度级别的程度,把握得死死的,那么前端代码是如何根据此 permissions 控制的,继续看代码,随便拉一个页面:
有个自定义方法
hasPermi
,顺藤摸瓜看下有个
hasPerm.js
,说明我已经写在注释里了:
这个钩子函数需要全局定义:
//全局定义语法参考
Vue.directive('hello', {
inserted(el) {
console.log(el);
如果是在html中定义,那么可以这么写:
Vue.directive("hello",function(el,binding,vnode){
el.style["color"]= binding.value;
因为这个
hasPermi
很多地方都会用到,所以肯定采用第一种方式:
后端权限控制粒度
如果你认为仅仅只是前端通过 控制按钮的显隐 来 限制操作权限 那就太天真了,不信的话我们试一下,把前端按钮保留不刷新,但同时在其他浏览器把该角色的某个按钮权限去除(修改数据库没用,因为取的是redis缓存),那么即使有编辑入口,接口也不会允许通过
看后端代码:
@PreAuthorize是security中用来进行权限控制的注解,
@ss.hasPermi('system:notice:edit')
其中的表达式,返回boolean类型:
/**
* 验证用户是否具备某权限
* @param permission 权限字符串
* @return 用户是否具备某权限
public boolean hasPermi(String permission) {
if (StringUtils.isEmpty(permission)) {
return false;
//通过request头部中的token获取redis中的User信息
LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions())) {
//如果缓存中无用户信息或者该用户也没权限信息,那么直接返回false
return false;
//判断是否包含该权限
return hasPermissions(loginUser.getPermissions(), permission);
如果是false则会直接返回403错误,前段会根据返回code弹出对应的错误:
export default {
'401': '认证失败,无法访问系统资源',
'403': '当前操作没有权限',
'404': '访问资源不存在',
'default': '系统未知错误,请反馈给管理员'
后端接口的权限判断都是基于redis缓存中的数据,所以 测试权限这一块的时候修改数据库的值是没用 的,好在权限的功能模块已经相对完善,能够满足复杂的权限管理,基本上不需要去修改什么。
权限数据解析
再看下第二步的生成动态路由部分:
看下这个路由内部是个什么玩样儿,输出看一下:
相信其他都好理解,就是有个 component 怎么会有这么多内容:
// 遍历后台传来的路由字符串,转换为组件对象
function filterAsyncRouter(asyncRouterMap, lastRouter = false, type = false) {
return asyncRouterMap.filter(route => {
if (type && route.children) {
route.children = filterChildren(route.children)
if (route.component) {
// Layout ParentView 组件特殊处理
if (route.component === 'Layout') {
route.component = Layout
} else if (route.component === 'ParentView') {
route.component = ParentView
} else {
//这里的component是一个url,所以直接调用路由懒加载方法注册路由
route.component = loadView(route.component)
if (route.children != null && route.children && route.children.length) {
route.children = filterAsyncRouter(route.children, route, type)
} else {
delete route['children']