sunny-rbac
v0.1.2
Published
![npm version](https://img.shields.io/npm/v/sunny-rbac) ![npm downloads](https://img.shields.io/npm/dm/sunny-rbac) ![license](https://img.shields.io/npm/l/sunny-rbac)
Downloads
2
Readme
sunny-rbac
为页面
和页面内操作
的提供权限控制支持
Installation
使用npm安装
npm i sunny-rbac
使用yarn安装
yarn add sunny-rbac
使用pnpm安装
pnpm add sunny-rbac
Usages
集成用例
与可拔插路由模块(sunny-pluggable-router)集成
使用自定义路由组件 AuthRoute
import { implement as routerImplement } from 'sunny-pluggable-router'
import { AuthRoute } from 'sunny-auth'
import { Route } from 'react-router'
import hashHistory from '../hashHistory'
/**
* 扩充 RouteConfig 类型增加auth属性
*/
declare module 'sunny-pluggable-router/dist/types/index.es' {
interface RouteConfig {
auth?: boolean
}
}
/**
* 为sunny-pluggable-router模块,使用自定义路由组件
* 自定义选择路由组件的逻辑,可以为路由增加特别功能
* 这里我们为路由配置增加了一个auth认证功能
*/
routerImplement({
customRoute: route => {
const isAdmin = true
if (isAdmin) {
// 适用于后台管理,后台管理项目默认启用认证路由
// eslint-disable-next-line @typescript-eslint/no-unnecessary-boolean-literal-compare
return route.auth === false ? Route : AuthRoute
} else {
// 适用于前端web应用
return route.auth ? AuthRoute : Route
}
},
})
实现认证逻辑
// 实现基本的登录认证
import { implement as AuthImplement } from 'sunny-auth'
AuthImplement({
authenticate: () => (isLogin() ? Promise.resolve() : Promise.reject()),
requireLogin: () => {
const pathname = routeConfig('login')?.path.toString()
const from = hashHistory.location
if (pathname && pathname !== from.pathname) {
console.debug('forward to ', location, ' from ', from)
hashHistory.push(pathname)
}
},
})
与授权路由模块集成
实现访问控制逻辑
import { implement as AuthImplement } from 'sunny-auth'
import {
getPrivileges,
getResources,
hasResource,
implement as RBACImplement,
} from 'sunny-rbac'
import { matchPath } from 'react-router'
import hashHistory from '../hashHistory'
RBACImplement({
// 因用例代码使用了hash history而不是browser history,所以这里重写了模块获取location.pathname的默认逻辑
currentResource: () => hashHistory.location.pathname,
})
AuthImplement({
authorize: routeProps =>
Promise.all([
// 准备好RBAC权限控制模块所需的resources资源信息,后面的查询都会用到
getResources()
// 准备好RBAC权限控制模块当前resources所需的privileges信息
.then(() => getPrivileges())
.then(() => {
/**
* 使用matchPath是为了处理route.path为数组的情况
*/
const match = matchPath(hashHistory.location.pathname, routeProps)
/**
* 查询当前菜单是否被授权访问
* 如果/parent被允许,那么/parent/child也被允许
*/
return (match && hasResource(match.path)) || Promise.reject()
}),
]),
deny: () => {
console.debug(
'The visitor is not allowed to go',
hashHistory.location,
'. Then go back.'
)
},
})
配置 sunny-rbac,对接后台权限系统接口。
import { implement as RBACImplement, clearCache } from 'sunny-rbac'
RBACImplement({
// 向后端权限系统查询所有可用资源
getResources: () => Promise.resolve([{ path: '/dashboard', id: 1 }]),
// 向后端权限系统查询某个资源所有可用权限
// 在运行时会用户的访问某些页面的行为而被调用
getPrivileges: (/* { id: resourceId } */) => Promise.resolve([{ title: '操作名称' }]),
// 查询用户是否为超级管理员,超管为上帝视角,拥有最高权力。所有权限查询都会通过
isRootUser() {
// roleId === 1 超级管理员
const roleId = 1
return Number(roleId) === 1
},
})
// 权限信息更新时,清空现有缓存,可以触发重新请求权限数据
// onPrivilegeUpdated(clearCache)
// onRequestLogin(clearCache)
// onSessionError(clearCache)
// onLogout(clearCache)
更多用例代码见 examples 和 storybook 文档
How it works
介绍当前项目与后端 RBAC 模型权限系统对接在一起的协作方式。
术语表
| 术语 | 别名 | 翻译 | |------|-------|-----------------------------------| | 一级权限 | 页面/资源 | 以页面为单位。体现为页面、页面路由、侧栏菜单 | | 二级权限 | 操作/权限 | 以可用操作为单位。体现为页面中的单个按钮、一组交互组件、一个逻辑块 |
一级权限
整个页面
页面路由
/sys/firstAuth
侧栏菜单
二级权限
单个按钮
一组交互组件
可以将这一组交互组件命名为“搜索”,意思为只要有“搜索”权限,即可以使用 这一组组件。
一个逻辑块
import { hasPrivilege } from 'sunny-rbac'
if (hasPrivilege('合计')) {
// do something else
}
了解协作方式
协作方式概述
先对路由访问进行控制,在对页面操作进行控制。 一个页面是否能访问,除了要检查登录态,还得检查路由对于当前用户来讲是否有权访问。 好在现在,可以利用自定义路由模块实现拦截、登录态查询、访问权限查询。
为了实现这些想法,设计了认证授权路由组件(sunny-auth), 权限控制模块(sunny-rbac)两个关键模块。 sunny-auth 用来路由拦截。sunny-rbac 用来提供对访问权限查询服务。
先了解一下基本工作流程。
页面访问控制流程
通用流程
访问路由 > 拦截访问 > 身份认证
正常流程
认证通过 > 允许访问
异常流程
认证失败 > 拒绝访问
页面操作控制流程
通用流程
操作权限 > 读取 > 查询
正常流程
有 > 通过 > 展示
异常流程
没有 > 拒绝 > 隐藏
在后台管理页面开发中的应用
新开发好的页面,通常已经定义好了路由信息,接下来就需要加入侧栏菜单,和为页面添加可用操作。
将新页面加入菜单
功能定位:权限路由 > 添加
为新页面添加可用操作权限
功能定位:权限路由 > 找到已添加的新页面 > 新增权限
注意“权限路由”处填写接口地址
根据页面的功能设计,将剩余的“操作”依次加入
Browser Compatibility
Changelog
See CHANGELOG.md