版本变更请查看 CHANGELOG
一个面向 Taro + React 的轻量权限库,提供:
- 资源-动作权限模型(Record<string, string[]>),支持通配符“*”与正则资源匹配
- 路由守卫与导航代理(navigateTo/redirectTo/switchTab),自动拦截无权限访问
- 初始化前 API 调用排队,避免“白屏/误伤渲染”与竞态问题
- React 生态集成:PermissionWrapper 组件与 useRoutePermission Hook
- 简单类型与事件机制,权限更新后自动刷新视图
本库依赖以下 peerDependencies:
- @tarojs/taro >= 3
- react >= 17
使用你熟悉的包管理器安装:
# pnpm
pnpm add poter
# npm
npm i poter
# yarn
yarn add poter导入:
import Poter, {
CPoter,
PoterAuthError,
PermissionWrapper,
useRoutePermission,
type PoterRoute,
type PoterGrantedPermission,
type PoterOptions,
} from "poter"import Poter, { type PoterRoute, type PoterGrantedPermission, type PoterOptions } from "poter"
const routes: PoterRoute[] = [
{ url: "/pages/article/index", requiredPermissions: [{ resource: "article", actions: ["read"] }] },
{ url: "/pages/sys/index", requiredPermissions: [{ resource: /^sys:.+$/, actions: ["manage"] }], oneOfPerm: true },
]
const grantedPermissions: PoterGrantedPermission = {
article: ["read"],
"sys:role": ["manage"],
}
const options: PoterOptions = {
navigateBackFallback: "/pages/index/index", // 可选:navigateBack 失败时跳转的 tab 页
}
Poter.init(routes, grantedPermissions, options)// 根据 url 判断是否可访问(自动去除 query/hash;若路由未配置权限,默认放行)
const canVisit = Poter.authenticationPath("/pages/article/index")
// 自定义校验(未初始化时默认返回 false)
const allowed = Poter.check({
requiredPermissions: [
{ resource: "article", actions: ["read"] },
{ resource: /^sys:.+$/, actions: ["manage"] },
],
oneOfPerm: true,
})
// 需要等待 init 完成后再鉴权
const allowedAsync = await Poter.check(
{ requiredPermissions: [{ resource: "article", actions: ["read"] }] },
{ waitInit: true },
)import { PoterAuthError } from "poter"
try {
await Poter.navigateTo({ url: "/pages/article/index" })
} catch (e) {
if (e instanceof PoterAuthError) {
// code === 401
}
}
// redirectTo / switchTab 同理;navigateBack 不做权限限制并立即执行import { useRoutePermission, PermissionWrapper } from "poter"
const { canAccess, loading, error, refresh } = useRoutePermission("/pages/article/index")
<PermissionWrapper
requiredPermissions={[{ resource: "article", actions: ["read"] }]}
backup={<span>无权限</span>}
loading={<span>加载中...</span>}
>
<YourComponent />
</PermissionWrapper>-
PoterGrantedPermission:Record<资源, 动作[]>,例如:
const perms = { article: ["read", "write"], "sys:role": ["manage"], product: ["*"], // 通配符:任意动作均可 }
-
PoterAuth.resource 支持 string 或 RegExp:
- string:直接从用户权限中读取该 key
- RegExp:对所有 key 做匹配,必须全部匹配项都满足 actions 要求
-
actions 判断规则:
- 若权限数组包含
"*",视为对该资源下所有动作放行 - 否则要求 actions 中的每个动作均包含在权限数组中
- 若权限数组包含
-
路由匹配会自动去除 query/hash,并忽略末尾斜杠(根路径除外)
-
路由未配置 requiredPermissions 时,默认放行
-
init(routes: PoterRoute[], grantedPermissions: PoterGrantedPermission, options?: PoterOptions): void
- 构造内部实例并触发事件通知(组件/Hook 会自动刷新)
- 初始化完成后会自动刷新排队中的调用
-
reset(): void
- 清除实例与任务队列(主要用于测试或登出重置)
-
updateGrantedPermission(grantedPermissions: PoterGrantedPermission): void
- 更新当前用户权限并触发刷新
- 若尚未初始化,会将更新入队,待
init完成后执行
-
authenticationPath(url: string): boolean
- 根据预设 routes 判断是否可访问
- 未初始化时返回
false
-
authRoute(url: string, options?: PoterAsyncOptions): boolean | Promise
- waitInit = false(默认):未初始化时直接返回 defaultValue(默认 false,不入队)
- waitInit = true:若未初始化则入队等待,最终返回真实鉴权结果(始终 Promise)
-
check(params: PoterAuthParams, options?: PoterAsyncOptions): boolean | Promise
- 自定义校验:传 requiredPermissions 与 oneOfPerm
- 未初始化且 waitInit = false 时返回 defaultValue(默认 false)
- waitInit = true 时入队等待 init 后返回真实结果
-
navigateTo / redirectTo / switchTab
- 导航前会进行权限校验,失败抛出
PoterAuthError(code: 401)
- 导航前会进行权限校验,失败抛出
-
navigateBack(options?: Taro.navigateBack.Option): Promise
- 不做权限限制,立即执行
- 若在
PoterOptions.navigateBackFallback中配置了路径,navigateBack失败时会switchTab到该页
队列语义:在 init 之前调用的鉴权/导航,会被排队等待初始化完成后串行执行,避免竞态问题。
可直接实例化,适合非单例场景或单元测试:
import { CPoter } from "poter"
const poter = new CPoter(routes, grantedPermissions, { navigateBackFallback: "/pages/index/index" })
poter.authenticationPath("/pages/article/index")
poter.updateGrantedPermission({ article: ["read"] })interface UseRoutePermissionOptions {
immediate?: boolean // 默认 true
defaultValue?: boolean // 默认 false
}返回:canAccess、loading、error、refresh
type PermissionWrapperProps = {
requiredPermissions?: Array<{ resource: string | RegExp; actions?: string[] }>
oneOfPerm?: boolean
backup?: React.ReactNode // 无权限时的兜底渲染
loading?: React.ReactNode // 鉴权等待中的兜底渲染
}- 内部通过
check({ waitInit: true })异步鉴权,init 前不会误放行 children - 权限初始化/变更后自动刷新
- PoterGrantedPermission、PoterAuth、PoterAuthParams、PoterRoute
- PoterOptions、PoterAsyncOptions
- PoterAuthError
要求 Node >= 20.19。
pnpm install
pnpm run test
pnpm run buildupdateUserPermission重命名为updateGrantedPermissionCPoter.authentication重命名为authenticationPathcheck未初始化时由返回true改为返回false;支持{ waitInit, defaultValue }选项- 导航失败改为抛出
PoterAuthError实例(仍含code: 401) navigateBack不再硬编码/pages/index/index,改为通过PoterOptions.navigateBackFallback配置- 新增
Poter.reset();CPoter从包入口正式导出
- 单例同步鉴权方法由
authentication重命名为authenticationPath init第二参数命名为grantedPermissions- 内部类由
CToter重命名为CPoter
- 未初始化行为(默认均为保守策略)
authenticationPath/check(waitInit=false)/authRoute(waitInit=false)均返回falsecheck/authRoute设置waitInit: true时入队等待- 导航 API 与
updateGrantedPermission会入队等待 init
- 导航异常:抛出
PoterAuthError - 正则资源:匹配到的所有资源都需满足 actions 判定
- 通配符:权限数组包含
"*"即放行该资源的所有动作
MIT © recvexi