sunny-acl
v0.0.3
Published
![npm version](https://img.shields.io/npm/v/sunny-acl) ![npm downloads](https://img.shields.io/npm/dm/sunny-acl) ![license](https://img.shields.io/npm/l/sunny-acl)
Downloads
4
Readme
sunny-acl
基于 acljs 进行再封装,在原有功能基础上,提供根据 路由path 收集 resources 能力。
Installation
使用npm安装
npm i sunny-acl
使用yarn安装
yarn add sunny-acl
使用pnpm安装
pnpm add sunny-acl
Usages
集成用例
为react router的Router组件定一个共享history实例,后面方便和认证路由进行协同工作。 hashHistory.ts 文件内容为
import { createHashHistory } from 'history'
export default createHashHistory()
实现认证与授权逻辑。 integrate.ts 文件内容为
import { implement as AuthImplement } from 'sunny-auth'
import { Action, implement as ACLImplement, isAllowed } from 'sunny-acl'
import hashHistory from './hashHistory'
ACLImplement({
ajaxPermissions: () =>
Promise.resolve({
roles: [
{ name: 'guest' },
{ name: 'member', parent: 'guest' },
{ name: 'admin' },
],
resources: [{ name: 'home' }],
rules: [
{
access: 'allow',
role: 'admin',
privileges: null,
resources: null,
},
{
access: 'allow',
role: 'member',
privileges: null,
resources: ['home'],
},
],
}),
getRole: () => sessionStorage.getItem('role'),
getPaths: () => ['/dashboard'] // 如果有条件,可以将所有页面路由path集合在一起生成 resources
})
AuthImplement({
authenticate: () => {
const isLogin = () => {
return sessionStorage.getItem('token')
? Promise.resolve()
: Promise.reject()
}
return isLogin()
},
requireLogin: () => {
hashHistory.push('/login')
},
authorize: isAllowed,
deny: () => {
console.debug('You are not allowed to go', history.location.pathname)
alert('拒绝访问')
hashHistory.goBack()
},
})
使用路由组件拦截访问
import React, { FC } from 'react'
import { Router, Route, Switch } from 'react-router'
import { AuthRoute } from 'sunny-auth'
import { Action } from 'sunny-acl'
import hashHistory from './hashHistory'
import './integrate.ts' // 载入配置逻辑,使认证逻辑正常工作
declare module 'react-router' {
interface RouteProps extends Action {}
}
const App: FC = () => (
<Router history={hashHistory}>
<Switch>
<AuthRoute path={'/'} exact resource="home">Home Page</AuthRoute>
<AuthRoute path={'/dashboard'}>Dashboard Page</AuthRoute>
<Route path={'/login'}>
Login Page
<button onClick={() => {
sessionStorage.setItem('token', 'xxx')
// 随机设定一个角色
sessionStorage.setItem('role', ['member', 'admin'].sort(() => .5 - Math.random()).pop())
hashHistory.goBack()
}}>登录</button>
</Route>
</Switch>
</Router>
)
更多集成用例
- Auth与ACL授权模块集成 的 storybook 文档
将权限规则与组件、代码块进行关联
假设权限配置如下所示
import { Permissions } from 'sunny-acl'
const permissions: Permissions = {
roles: [
// ...
{ name: 'manager' },
// ...
],
resources: [
// ...
{ name: 'product' }
// ...
],
rules: [
// ...
{
access: 'allow',
role: 'manager',
privileges: ['add', 'delete'],
resources: ['product'],
},
// ...
],
}
与组件绑定
import React, { FC } from 'react'
import { Privilege } from 'sunny-acl'
const Components: FC = () => <>
<Privilege path="product/add"><button>添加</button></Privilege>
<Privilege resource="product" privilege="delete"><button>删除</button></Privilege>
</>
与逻辑块关联
import React, { useEffect, FC } from 'react'
import { isAllowedSync } from 'sunny-acl'
const Components: FC = () => {
useEffect(() => {
if (isAllowedSync({ path: 'product/add' })) {
// do something else
}
}, [])
return <></>
}
How it works
资源和权限是集中声明,还是分散写在路由配置中?
集中和分散方式之间的比较
- 资源和权限是集中声明
- 由path解析器决定当前路由的resource、privilege信息
- 无法提取信息时可以由路由配置作为补充
- 需要预先定义ACL权限列表
- 既然会由后端存储,那么分散写到路由配置中就不是个好的选择
- 由path解析器决定当前路由的resource、privilege信息
- 分散写在路由配置中
- 由路由嵌套关系决定resource继承关系
- 由路由决定当前是resource还是privilege
- 需要遍历树形结构路由信息表来生成resource继承关系
最终决定
- 考虑未来权限信息由后端存储,可以考虑先集中声明
- path解析器作为确认resource、privilege主要方式,路由配置中携带这两个字段作为覆盖/补充
- route path可以确定resource继承关系,确定privilege
- 如果选择自动生成,无论是否为继承关系,resource关键词都不可以重复出现
- route path可以确定resource继承关系,确定privilege
- 如果想要生成resources所有资源信息,可以遍历所有路由配置,结合path解析器后生成
Browser Compatibility
Changelog
See CHANGELOG.md