上篇图文讲输了创建uniCloud admin项目的基本过程,连接:https://blog.csdn.net/weixin_50853984/article/details/117122015,
现在我们的数据库user表中只有一个用户,并且角色是超级管理员.无法更改其超级管理员的角色(除非直接更改数据库,或者修改代码)
关于用户角色权限这块官网也有进行讲解 连接:https://uniapp.dcloud.io/uniCloud/admin?id=%e7%94%a8%e6%88%b7-%e8%a7%92%e8%89%b2-%e6%9d%83%e9%99%90 但是我按照官网步骤进行时却遇到了权限不足的问题
新建角色,用户,以及给角色配置权限
我们在项目刚刚创建完成的时候创建了一个admin的用户,该用户是自带超级管理员权限的,可以干任何事,我们用admin用户登录系统后分别创建一个新用户(user),角色(角色id:test,角色名称:测试角色),以及权限若干:(为了测试创建了4个权限,分别为用户管理权限:user_edit,角色管理权限:role_edit,权限管理:permissions_edit,菜单管理:menu_edit).权限添加页面
在创建用户时给改用户分配测试角色,登录创建好的用户后会出现提示.
原因是虽然给用户分配了角色,但是没有给角色分配权限,所以需要给角色设置一个用户管理的权限进行测试,可能会进行频繁的账号切换,建议开一个无痕模式的窗口登录测试
在菜单管理中给用户管理的菜单选项添加用户管理权限这样就user用户登录后台时就可以看到用户管理菜单了
先整理一下权限设置步骤:
- 菜单管理中给对应的菜单选项添加对应的权限,拥有该权限的角色才能访问此菜单(如用户管理菜单添加用户管理权限)
- 在角色管理中给测试角色添加了用户管理权限
- 在用户管理中给我们新建的user用户分配了测试角色,然后我们在登录user用户之后就可以看到角色管理菜单了如上图
终于权限设置完成了,吗? 还没有,user用户点击用户菜单时我们看到的用户列表是这样的:
同样在新增用户时一样会说权限效验未通过,禁止访问之类的,查看官网后发现官网的说法是:
连接:提示效验未通过
"因为刚刚仅为该用户赋予了访问菜单的权限。还未赋予访问uni-id-users表的阅读权限"这个'访问uni-id-users表的阅读权限'需要认真阅读官网文档:https://uniapp.dcloud.io/uniCloud/schema?id=permission 数据权限系统这里就不多做解释
设置方法为打开Hbuilder X 我们的项目打开文件 uniCloud->database->uni-id-users.schema.json 文件 按照官方提示的在"required" 节点后面添加"permission"权限节点 分别为读取,创建,更新,和删除权限,我们现在只需要读取权限,所以先把read权限改为true(所有用户(角色)都可以读取),更改完成后右键文件名,点击上传DB schema
"permission": {
"read": true,
"create":false,
"update":false,
"delete": false
},
上传成功后刷新user的页面,额...还是继续显示"权限效验未通过"...... 然后通过我仔细的观察之后发现Hbuilder X uniCloud控制台中在发请求的时候是向两张表发送的请求如图:
刚刚users表的读取权限已经给了,应该没问题,roles表的权限貌似并没有设置.然后我打开uniCloud->database->uni-id-roles.schema.json 文件后,发现4个表权限全部设置为false.重复更改user表权限的步骤,更改roles表权限,将读取权限置为true上传,上传成功后刷新后台页面,user列表就出现了
创建的两个用户都在,到这里新建用户的权限问题貌似大致解决了额,
其实在上面更改表的读取权限时我们直接吧read置为true了,这样所有人都可以读取,不太安全,所以稍微改进一点如下代码:
"permission": {
"read": "'user_edit' in auth.permission",
"create":false,
"update":false,
"delete": false
},
这里的权限设置规则为,拥有 "user_edit"权限的用户才可以读取这张表的数据,将users表和roles表修改成这样,权限设置就算完整了
另一个权限的设置方式
在获取到用户列表后,我想再添加一个用户,填完必填之后提交数据发现报错弹框了禁止访问.emmmm..................
权限管理用户,添加一个用户不算过分吧.然后再对比了获取用户列表和提交新建用户表单的源码后发现,这是两个不同的操作云数据库的方式 云数据库有两种方式进行操作参考:https://uniapp.dcloud.io/uniCloud/hellodb?id=%e6%93%8d%e4%bd%9c%e6%95%b0%e6%8d%ae%e5%ba%93%e7%9a%842%e7%a7%8d%e6%96%b9%e6%b3%95
这里的提交表单用到的是云函数操作数据库,获取列表用到是客户端访问云数据库,称为clientDB。所以获取列表的权限在数据库的表设计上设置权限即可,
而这里云函数操作数据库显然是uni-id这个插件做的拦截 uin-id参考:https://uniapp.dcloud.io/uniCloud/uni-id
打开项目 uniCloud->cloudfunctions->uni-admin
这个中间件中进行了权限效验拦截,代码中是只有拥有'admin'角色的人和拥有'当前路径权限的'才能访问,
module.exports = () => {
// 返回中间件函数
return async function permission(ctx, next) {
if (!ctx.auth || !ctx.auth.role.includes('admin') && !ctx.auth.permission.includes(ctx.event.action)) {
ctx.throw('FORBIDDEN', '禁止访问')
}
await next() // 执行后续中间件
}
}
两个解决方案:
- 添加一个当前路径的权限
- 改造这个权限拦截代码
修改权限拦截代码
module.exports = () => {
// 返回中间件函数
return async function permission(ctx, next) {
if (!ctx.auth || !ctx.auth.role.includes('admin')) { // 如果请求接口的人不是admin 就检查该接口是否有调用权限
if(!ctx.event.permission) await next() // 如果么有权限 执行后续中间件
if (ctx.event.permission && !ctx.auth.permission.includes(ctx.event.permission)) {
ctx.throw('FORBIDDEN', '权限不足,禁止访问')
}
}
// if (!ctx.auth || !ctx.auth.role.includes('admin') && !ctx.auth.permission.includes(ctx.event
// .action)) {
// ctx.throw('FORBIDDEN', '禁止访问')
// }
await next() // 执行后续中间件
}
}
// 前端调用接口的代码
let res = await that.$request('assets_storage/saveImage',data,"upload",{ functionName: 'uni-cloud-router'})
if(res.id){
uni.showToast({
title:'图片储存成功',
icon:'none'
})
}
// 修改一下$request方法 文件位置 js_sdk->uni-admin->request.js
export function request(action, data,permission,{ functionName = 'uni-admin',showModal = true} = {}) {
return uniCloud.callFunction({
name: functionName,
data: {
action,
permission, // 调取接口所需的权限
data
}
}).then(({result}) => {
if (!result) {
return Promise.resolve(result)
}
if (result.code) {
reLaunchToLogin(result.code)
// const err = new Error(result.message)
// err.code = result.code
const err = result
return Promise.reject(err)
}
const {
token,
tokenExpired
} = result
if (token && tokenExpired) {
store.commit('user/SET_TOKEN', {
token,
tokenExpired
})
}
return Promise.resolve(result)
}).catch(err => {
const that = this
showModal && uni.showModal({
content: err.message || '请求服务失败',
showCancel: false
})
// #ifdef H5
const noDebugPages = ['/pages/login/login', '/pages/init/init']
const {
path
} = this.$route
if (debugOptions && debugOptions.enable === true && noDebugPages.indexOf(path) === -1) {
store.dispatch('error/add', {
err: err.toString(),
info: '$request("' + action + '")',
route: '',
time: new Date().toLocaleTimeString()
})
}
// #endif
return Promise.reject(err)
})
}
这样只需要在调用url化接口的时候传入该接口需要的权限就可以做到云函数的权限控制了