@lark-apaas/auth-sdk 0.1.0-alpha.0 → 0.1.0-alpha.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -14,18 +14,16 @@ yarn add @lark-apaas/auth-sdk
14
14
 
15
15
  ```tsx
16
16
  import React from 'react';
17
- import { AuthProvider, Can, useAbility } from '@lark-apaas/auth-sdk';
17
+ import { AuthProvider, Can, useAuthAbility } from '@lark-apaas/auth-sdk';
18
18
 
19
19
  export default function App() {
20
20
  return (
21
21
  <AuthProvider
22
22
  config={{
23
23
  permissionApi: {
24
- baseUrl: 'http://localhost:3000',
25
- endpoint: '/api/users/:userId/permissions',
26
- // 可选:apiToken、timeout、headers、withCredentials
24
+ timeout: 5000,
27
25
  },
28
- autoFetch: true,
26
+ enable: true,
29
27
  onError: (e) => console.error(e),
30
28
  }}
31
29
  >
@@ -35,13 +33,13 @@ export default function App() {
35
33
  }
36
34
 
37
35
  function Home() {
38
- const ability = useAbility();
36
+ const ability = useAuthAbility();
39
37
  return (
40
38
  <div>
41
- <Can I="read" a="Dashboard">
39
+ <Can I="admin" a="@role">
42
40
  <div>可见的仪表盘</div>
43
41
  </Can>
44
- <button disabled={ability.cannot('create', 'Task')}>创建任务</button>
42
+ <button disabled={ability.cannot('reader', '@role')}>创建任务</button>
45
43
  </div>
46
44
  );
47
45
  }
@@ -55,24 +53,18 @@ function Home() {
55
53
  - **作用**: 提供 `Ability` 与权限状态上下文,自动/手动拉取权限。
56
54
  - **Props**:
57
55
  - `config?: AuthSdkConfig`
58
- - `noPermissionPath?: string` 无权限时的导航路径
59
56
  - `permissionApi?: PermissionApiConfig` 拉取权限接口配置
60
- - `baseUrl?: string`
61
- - `endpoint?: string`,支持 `:userId` 占位
62
57
  - `timeout?: number`,默认 5000ms
63
- - `headers?: Record<string,string>`
64
- - `apiToken?: string` 自动加到 Authorization
65
- - `withCredentials?: boolean`,默认 true
66
- - `autoFetch?: boolean` 是否初始化自动拉取
58
+ - `headers?: Record<string,string>` 自定义请求头
59
+ - `enable?: boolean` 是否启用权限 SDK,默认 false
67
60
  - `onError?: (error: Error) => void`
68
61
  - `onSuccess?: (data: PermissionApiResponse) => void`
69
62
  - `children: React.ReactNode`
70
63
 
71
64
  示例:
72
65
  ```tsx
73
- <AuthProvider userId="user-123" config={{
74
- permissionApi: { endpoint: '/api/permissions' },
75
- autoFetch: true,
66
+ <AuthProvider config={{
67
+ enable: true,
76
68
  }}>
77
69
  <App />
78
70
  {/* Can/Hook 在其子树中生效 */}
@@ -82,121 +74,30 @@ function Home() {
82
74
  ### useAuth
83
75
  - **作用**: 访问权限状态与方法。
84
76
  - **返回**:
85
- - `permissions: Permission[]`
86
- - `roles: string[]`
87
- - `userId: string | null`
88
- - `setUserId(userId: string): void`
89
- - `isLoading: boolean`
90
- - `error: Error | null`
91
- - `fetchPermissions(userId?: string): Promise<void>` 手动拉取
92
- - `refetch(): Promise<void>` 按当前 `userId` 重新拉取
77
+ - `ability: Ability` CASL `Ability` 实例
78
+ - `isLoading: boolean` 是否正在加载权限数据
79
+ - `error: Error | null` 最近一次加载错误(如果有)
80
+ - `fetchPermissions(userId?: string): Promise<void>` 手动拉取权限数据
93
81
 
94
82
  ```tsx
95
- const { permissions, roles, isLoading, refetch } = useAuth();
83
+ const { ability, isLoading, error, fetchPermissions } = useAuth();
96
84
  ```
97
85
 
98
- ### useAbility
86
+ ### useAuthAbility
99
87
  - **作用**: 获取 CASL `Ability` 实例,使用 `ability.can(action, subject)` 做任意判断。
100
88
 
101
89
  ```tsx
102
- const ability = useAbility();
103
- const canCreate = ability.can('create', 'Task');
90
+ const ability = useAuthAbility();
91
+ const canCreate = ability.can('Editor', '@role');
104
92
  ```
105
93
 
106
94
  ### Can 组件(来自 @casl/react 的 Contextual Can)
107
95
  - **作用**: 条件渲染,只有当 `I` 对 `a` 可操作时才渲染子内容;也支持 render prop。
108
96
 
109
97
  ```tsx
110
- <Can I="delete" a="Task">
98
+ <Can I="Editor" a="@role">
111
99
  <button>删除任务</button>
112
100
  </Can>
113
-
114
- <Can I="download" a="Report">{(allowed) => (
115
- <button disabled={!allowed}>下载报表</button>
116
- )}</Can>
117
- ```
118
-
119
- ### 批量权限判断:useCanPermission / CanPermission
120
- - `useCanPermission({ permissions, or })`:一次检查多个权限;`or=true` 表示任一满足即可,否则默认全部需要满足。
121
- - `CanPermission`:同上但以组件方式使用,支持 children 或 render prop。
122
-
123
- ```tsx
124
- const allowed = useCanPermission({
125
- permissions: [
126
- { action: 'read', subject: 'Report' },
127
- { action: 'download', subject: 'Report' },
128
- ],
129
- or: false,
130
- });
131
-
132
- <CanPermission
133
- permissions={[{ action: 'manage', subject: 'Task' }, { action: 'delete', subject: 'Task' }]}>
134
- <BulkActions />
135
- </CanPermission>
136
- ```
137
-
138
- ### 角色判断:useCanRole / CanRole
139
- - 角色被映射为特殊 subject `@role` 下的 action。
140
- - `useCanRole({ roles, and })`:是否拥有指定多个角色;`and=true` 表示需要同时具备。
141
- - `CanRole`:以组件形式使用。
142
-
143
- ```tsx
144
- const isAdmin = useCanRole({ roles: ['admin_role'] });
145
-
146
- <CanRole roles={[ 'admin_role', 'ops_role' ]} and>
147
- <DangerZone />
148
- </CanRole>
149
- ```
150
-
151
- ### 路由守卫:CanRoute
152
- - **作用**: 路由级别的权限守卫,支持权限和角色双重检查,无权限时可自动重定向。
153
- - **Props**:
154
- - `permissions?: Array<{ action: string; subject: string }>` 需要检查的权限列表
155
- - `roles?: string[]` 需要检查的角色列表
156
- - `children: React.ReactNode` 受保护的内容
157
- - `fallback?: React.ReactNode` 无权限时渲染的内容(优先级最高)
158
- - `redirectTo?: string` 无权限时重定向的路径(优先级次之)
159
- - 如果既没有 `fallback` 也没有 `redirectTo`,会尝试使用 `AuthProvider` 配置的 `noPermissionPath`
160
- - 如果都没有配置,则返回 `null`
161
-
162
- ```tsx
163
- import { CanRoute } from '@lark-apaas/auth-sdk';
164
- import { Routes, Route } from 'react-router-dom';
165
-
166
- // 基础用法:权限检查
167
- <CanRoute permissions={[{ action: 'read', subject: 'Dashboard' }]}>
168
- <Dashboard />
169
- </CanRoute>
170
-
171
- // 角色检查
172
- <CanRoute roles={['admin', 'manager']}>
173
- <AdminPanel />
174
- </CanRoute>
175
-
176
- // 自定义重定向
177
- <CanRoute
178
- permissions={[{ action: 'manage', subject: 'User' }]}
179
- redirectTo="/unauthorized"
180
- >
181
- <UserManagement />
182
- </CanRoute>
183
-
184
- // 自定义 fallback 内容
185
- <CanRoute
186
- roles={['admin']}
187
- fallback={<div>您没有管理员权限</div>}
188
- >
189
- <AdminSettings />
190
- </CanRoute>
191
-
192
- // 在路由中使用
193
- <Routes>
194
- <Route path="/admin" element={
195
- <CanRoute permissions={[{ action: 'manage', subject: 'Task' }]}>
196
- <AdminPage />
197
- </CanRoute>
198
- } />
199
- </Routes>
200
101
  ```
201
102
 
202
103
  ### PermissionClient
@@ -232,20 +133,16 @@ updateAbility(ability, { permissions: [{ id: 'p1', name: 'Task Read', sub: 'Task
232
133
  ---
233
134
 
234
135
  ## 类型与再导出
235
- - 从本包导出的类型:`Action`、`Subject`、`Permission`、`UserRole`、`PermissionApiResponse`、`PermissionApiConfig`、`AuthSdkConfig`、`CaslRule`。
236
- - 便捷再导出:`Ability`、`AbilityBuilder`、`AbilityClass`(来自 `@casl/ability`)。
136
+ - 从本包导出的类型:`PermissionApiResponse`、`PermissionApiConfig`、`AuthSdkConfig`、`CaslRule`。
137
+ - 便捷再导出:`MongoAbility`, `AbilityBuilder`, `AbilityClass`(来自 `@casl/ability`)。
237
138
 
238
139
  ---
239
140
 
240
141
  ## 集成建议与最佳实践
241
- - **权限接口返回**:`{ userId, roles: (string|UserRole)[], permissions: Permission[] }`,其中 `roles` 支持字符串或对象;SDK 会标准化为字符串数组。
142
+ - **权限接口返回**:`{ role_ids: string[] }`。
242
143
  - **错误处理**:实现 `onError` 上报或提示;`onSuccess` 可做埋点。
243
144
  - **渲染时机**:根据 `useAuth()` 的 `isLoading`/`error` 渲染 Loading/Error 页,避免闪烁。
244
- - **与路由结合**:使用 `CanRoute` 组件做页面级访问控制,支持自动重定向和自定义 fallback 内容。
245
- - **路由守卫最佳实践**:
246
- - 优先使用 `fallback` 属性展示友好的无权限提示
247
- - 使用 `redirectTo` 重定向到专门的错误页面
248
- - 在 `AuthProvider` 中配置全局的 `noPermissionPath` 作为兜底
145
+ - **与路由结合**:页面级的访问控制需要结合路由库(如 `react-router-dom`)和 `useAuthAbility` hook 来自行实现。
249
146
 
250
147
  ---
251
148
 
@@ -253,16 +150,16 @@ updateAbility(ability, { permissions: [{ id: 'p1', name: 'Task Read', sub: 'Task
253
150
 
254
151
  ### 菜单按权限过滤
255
152
  ```tsx
256
- import { useAbility } from '@lark-apaas/auth-sdk';
153
+ import { useAuthAbility } from '@lark-apaas/auth-sdk';
257
154
 
258
155
  const menus = [
259
- { name: 'Dashboard', path: '/dashboard', p: { action: 'read', subject: 'Dashboard' } },
260
- { name: 'Users', path: '/users', p: { action: 'read', subject: 'User' } },
261
- { name: 'Settings', path: '/settings', p: { action: 'manage', subject: 'Settings' } },
156
+ { name: 'Dashboard', path: '/dashboard', p: { action: 'Editor', subject: '@role' } },
157
+ { name: 'Users', path: '/users', p: { action: 'Admin', subject: '@role' } },
158
+ { name: 'Settings', path: '/settings', p: { action: 'Admin', subject: '@role' } },
262
159
  ];
263
160
 
264
161
  function Nav() {
265
- const ability = useAbility();
162
+ const ability = useAuthAbility();
266
163
  return (
267
164
  <nav>
268
165
  {menus.map(m => ability.can(m.p.action, m.p.subject) && (
@@ -273,79 +170,13 @@ function Nav() {
273
170
  }
274
171
  ```
275
172
 
276
- ### 批量操作区
277
- ```tsx
278
- import { BatchCan } from '@lark-apaas/auth-sdk';
279
-
280
- <BatchCan permissions={[{ action: 'delete', subject: 'Task' }, { action: 'manage', subject: 'Task' }]}>
281
- <div className="bulk-actions">
282
- <button>批量删除</button>
283
- <button>导出全部</button>
284
- </div>
285
- </BatchCan>
286
- ```
287
-
288
- ### 路由级权限控制
289
- ```tsx
290
- import { CanRoute } from '@lark-apaas/auth-sdk';
291
- import { Routes, Route, Navigate } from 'react-router-dom';
292
-
293
- function App() {
294
- return (
295
- <Routes>
296
- {/* 公开路由 */}
297
- <Route path="/" element={<HomePage />} />
298
- <Route path="/login" element={<LoginPage />} />
299
-
300
- {/* 受保护的路由 */}
301
- <Route path="/dashboard" element={
302
- <CanRoute permissions={[{ action: 'read', subject: 'Dashboard' }]}>
303
- <Dashboard />
304
- </CanRoute>
305
- } />
306
-
307
- {/* 管理员路由 */}
308
- <Route path="/admin" element={
309
- <CanRoute
310
- roles={['admin']}
311
- fallback={<Navigate to="/unauthorized" replace />}
312
- >
313
- <AdminPanel />
314
- </CanRoute>
315
- } />
316
-
317
- {/* 多权限检查 */}
318
- <Route path="/reports" element={
319
- <CanRoute
320
- permissions={[
321
- { action: 'read', subject: 'Report' },
322
- { action: 'export', subject: 'Report' }
323
- ]}
324
- redirectTo="/no-access"
325
- >
326
- <ReportsPage />
327
- </CanRoute>
328
- } />
329
-
330
- {/* 错误页面 */}
331
- <Route path="/unauthorized" element={<UnauthorizedPage />} />
332
- <Route path="/no-access" element={<NoAccessPage />} />
333
- </Routes>
334
- );
335
- }
336
- ```
337
-
338
173
  ---
339
174
 
340
175
  ## 常见问题(FAQ)
341
- - **如何做角色判断?** 使用 `useCanRole`/`CanRole`;角色被映射为对特殊 subject `@role` 的 action
342
- - **如何使用路由守卫?** 使用 `CanRoute` 组件包装需要保护的路由内容,支持权限和角色双重检查。
343
- - **CanRoute 的重定向优先级?** `fallback` > `redirectTo` > `noPermissionPath`(AuthProvider 配置)> `null`。
344
- - **CanRoute 需要 react-router-dom 依赖吗?** 是的,因为使用了 `Navigate` 和 `useLocation`,请确保项目中已安装。
176
+ - **如何做角色判断?** 角色被映射为对特殊 subject `@role` 的 action。你可以使用 `ability.can('admin_role', '@role')` 来判断当前用户是否拥有 `admin_role` 角色。
177
+ - **如何实现路由守卫?** 由于 `CanRoute` 组件已移除,您需要结合您使用的路由库(如 `react-router-dom`)和 `useAuthAbility` hook 来手动实现路由守卫。通过在路由渲染前检查权限,然后决定是否渲染组件或重定向。
345
178
 
346
179
  ---
347
180
 
348
181
  ## 许可
349
182
  MIT
350
-
351
-
@@ -1,59 +1,19 @@
1
1
  import React from 'react';
2
- import { Ability } from '@casl/ability';
3
- import type { AuthSdkConfig, Permission } from './types';
2
+ import { MongoAbility } from '@casl/ability';
3
+ import type { AuthSdkConfig } from './types';
4
4
  /**
5
5
  * Ability Context - 用于在组件树中共享 Ability 实例
6
6
  */
7
- export declare const AbilityContext: React.Context<Ability<import("@casl/ability").AbilityTuple, import("@casl/ability").MongoQuery>>;
8
- /** 权限点位鉴权相关的 Hooks 和组件 */
9
- /**
10
- * Can 组件 - 基于 Context 的条件渲染组件
11
- * 使用 @casl/react 的 createContextualCan 创建,复用 CASL 的官方实现
12
- */
13
- export declare const Can: React.FunctionComponent<import("@casl/react").BoundCanProps<Ability<import("@casl/ability").AbilityTuple, import("@casl/ability").MongoQuery>>>;
14
- export interface UseCanPermissionProps {
15
- permissions?: Array<{
16
- action: string;
17
- subject: string;
18
- }>;
19
- or?: boolean;
20
- }
21
- export interface CanPermissionProps extends UseCanPermissionProps {
22
- children: React.ReactNode | ((allowed: boolean) => React.ReactNode);
23
- }
24
- export declare const useCanPermission: ({ permissions, or }: UseCanPermissionProps) => boolean;
25
- export declare function CanPermission({ permissions, children, or }: {
26
- permissions: Array<{
27
- action: string;
28
- subject: string;
29
- }>;
30
- children: React.ReactNode | ((allowed: boolean) => React.ReactNode);
31
- or?: boolean;
32
- }): import("react/jsx-runtime").JSX.Element | null;
33
- /** 角色鉴权相关的 Hooks 和组件 */
34
- export interface UseCanRoleProps {
35
- roles?: string[];
36
- and?: boolean;
37
- }
38
- export declare const useCanRole: ({ roles, and }: UseCanRoleProps) => boolean;
39
- export interface CanRoleProps extends UseCanRoleProps {
40
- children: React.ReactNode | ((allowed: boolean) => React.ReactNode);
41
- }
42
- export declare const CanRole: ({ roles, and, children }: CanRoleProps) => import("react/jsx-runtime").JSX.Element | null;
7
+ export declare const AbilityContext: React.Context<MongoAbility<import("@casl/ability").AbilityTuple, import("@casl/ability").MongoQuery>>;
43
8
  /**
44
9
  * Auth 状态 Context 类型定义
45
10
  * 存储权限数据和加载状态
46
11
  */
47
12
  interface AuthStateContextValue {
48
- noPermissionPath?: string;
49
- permissions: Permission[];
50
- roles: string[];
51
- userId: string | null;
52
- setUserId: (userId: string) => void;
13
+ ability: MongoAbility;
53
14
  isLoading: boolean;
54
15
  error: Error | null;
55
16
  fetchPermissions: (userId?: string) => Promise<void>;
56
- refetch: () => Promise<void>;
57
17
  }
58
18
  /**
59
19
  * Auth Provider Props
@@ -61,7 +21,6 @@ interface AuthStateContextValue {
61
21
  export interface AuthProviderProps {
62
22
  children: React.ReactNode;
63
23
  config?: AuthSdkConfig;
64
- userId?: string;
65
24
  }
66
25
  /**
67
26
  * Auth Provider 组件
@@ -110,14 +69,14 @@ export declare function AuthProvider({ children, config }: AuthProviderProps): i
110
69
  */
111
70
  export declare function useAuth(): AuthStateContextValue;
112
71
  /**
113
- * useAbility Hook - 获取 Ability 实例
72
+ * useAuthAbility Hook - 获取 Ability 实例
114
73
  *
115
74
  * @example
116
75
  * ```tsx
117
- * import { useAbility } from '@lark-apaas/auth-sdk';
76
+ * import { useAuthAbility } from '@lark-apaas/auth-sdk';
118
77
  *
119
78
  * function MyComponent() {
120
- * const ability = useAbility();
79
+ * const ability = useAuthAbility();
121
80
  *
122
81
  * return (
123
82
  * <button disabled={ability.cannot('create', 'Task')}>
@@ -127,32 +86,43 @@ export declare function useAuth(): AuthStateContextValue;
127
86
  * }
128
87
  * ```
129
88
  */
130
- export declare function useAbility(): Ability;
89
+ export declare function useAuthAbility(): MongoAbility;
131
90
  /**
132
- * usePermissions Hook - 获取权限列表
91
+ * Can Component - 基于 Ability 实例的条件渲染组件
133
92
  *
134
93
  * @example
135
94
  * ```tsx
95
+ * import { Can } from '@lark-apaas/auth-sdk';
96
+ *
136
97
  * function MyComponent() {
137
- * const permissions = usePermissions();
138
- * return <div>You have {permissions.length} permissions</div>;
98
+ * return (
99
+ * <Can I="Admin" a="@role">
100
+ * <TaskList />
101
+ * </Can>
102
+ * );
139
103
  * }
140
104
  * ```
141
105
  */
142
- export declare function usePermissions(): Permission[];
106
+ export declare const Can: React.FunctionComponent<import("@casl/react").BoundCanProps<MongoAbility<import("@casl/ability").AbilityTuple, import("@casl/ability").MongoQuery>>>;
143
107
  /**
144
- * useRoles Hook - 获取角色列表
108
+ * CanRole Component - 基于 Ability 实例的角色条件渲染组件
145
109
  *
146
110
  * @example
147
111
  * ```tsx
112
+ * import { CanRole } from '@lark-apaas/auth-sdk';
113
+ *
148
114
  * function MyComponent() {
149
- * const roles = useRoles();
150
- * return <div>Your roles: {roles.join(', ')}</div>;
115
+ * return (
116
+ * <CanRole I="Admin">
117
+ * <TaskList />
118
+ * </CanRole>
119
+ * );
151
120
  * }
152
121
  * ```
153
122
  */
154
- export declare function useRoles(): string[];
155
- export declare function useUserId(): [string | null, (userId: string) => void];
156
- export declare function useNoPermissionPath(): string | undefined;
123
+ export declare const CanRole: ({ children, I, }: {
124
+ children: React.ReactNode;
125
+ I: string;
126
+ }) => import("react/jsx-runtime").JSX.Element;
157
127
  export {};
158
128
  //# sourceMappingURL=AuthProvider.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"AuthProvider.d.ts","sourceRoot":"","sources":["../src/AuthProvider.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"AuthProvider.d.ts","sourceRoot":"","sources":["../src/AuthProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAMN,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAK7C;;GAEG;AACH,eAAO,MAAM,cAAc,uGAE1B,CAAC;AAEF;;;GAGG;AACH,UAAU,qBAAqB;IAC7B,OAAO,EAAE,YAAY,CAAC;IACtB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,gBAAgB,EAAE,CAAC,MAAM,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACtD;AAOD;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,MAAM,CAAC,EAAE,aAAa,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,YAAY,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,iBAAiB,2CA2DnE;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,OAAO,IAAI,qBAAqB,CAQ/C;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,cAAc,IAAI,YAAY,CAE7C;AAED;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,GAAG,sJAA+C,CAAC;AAEhE;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,OAAO,GAAI,kBAGrB;IACD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,CAAC,EAAE,MAAM,CAAC;CACX,4CAIA,CAAC"}
@@ -1,70 +1,25 @@
1
- import { Fragment, jsx } from "react/jsx-runtime";
1
+ import { jsx } from "react/jsx-runtime";
2
2
  import { createContext, useCallback, useContext, useEffect, useState } from "react";
3
- import { createContextualCan } from "@casl/react";
4
3
  import { ROLE_SUBJECT, createAbility, updateAbility } from "./ability-factory.js";
5
4
  import { PermissionClient } from "./permission-client.js";
5
+ import { createContextualCan } from "@casl/react";
6
6
  const AbilityContext = /*#__PURE__*/ createContext(createAbility({
7
7
  permissions: [],
8
8
  roles: []
9
9
  }));
10
- const Can = createContextualCan(AbilityContext.Consumer);
11
- const useCanPermission = function({ permissions, or }) {
12
- const ability = useAbility();
13
- let allowed = false;
14
- allowed = or ? !permissions || !permissions.length || permissions.length > 0 && permissions.some(({ action, subject })=>ability.can(action, subject)) : !permissions || !permissions.length || permissions.length > 0 && permissions.every(({ action, subject })=>ability.can(action, subject));
15
- return !!allowed;
16
- };
17
- function CanPermission({ permissions, children, or }) {
18
- const allowed = useCanPermission({
19
- permissions,
20
- or
21
- });
22
- if ('function' == typeof children) return /*#__PURE__*/ jsx(Fragment, {
23
- children: children(allowed)
24
- });
25
- return allowed ? /*#__PURE__*/ jsx(Fragment, {
26
- children: children
27
- }) : null;
28
- }
29
- const useCanRole = function({ roles, and }) {
30
- const ability = useAbility();
31
- let allowed = false;
32
- allowed = and ? !roles || 0 === roles.length || roles.length > 0 && roles.every((role)=>ability.can(role, ROLE_SUBJECT)) : !roles || 0 === roles.length || roles.length > 0 && roles.some((role)=>ability.can(role, ROLE_SUBJECT));
33
- return !!allowed;
34
- };
35
- const CanRole = function({ roles, and, children }) {
36
- const allowed = useCanRole({
37
- roles,
38
- and
39
- });
40
- if ('function' == typeof children) return /*#__PURE__*/ jsx(Fragment, {
41
- children: children(allowed)
42
- });
43
- return allowed ? /*#__PURE__*/ jsx(Fragment, {
44
- children: children
45
- }) : null;
46
- };
47
10
  const AuthStateContext = /*#__PURE__*/ createContext(null);
48
11
  function AuthProvider({ children, config }) {
49
12
  const [ability] = useState(()=>createAbility({}));
50
- const [permissions, setPermissions] = useState([]);
51
- const [roles, setRoles] = useState([]);
52
- const [userId, setUserId] = useState(null);
53
13
  const [isLoading, setIsLoading] = useState(false);
54
14
  const [error, setError] = useState(null);
55
15
  const [client] = useState(()=>new PermissionClient(config?.permissionApi));
56
- const fetchPermissions = useCallback(async (uid)=>{
16
+ const fetchPermissions = useCallback(async ()=>{
57
17
  setIsLoading(true);
58
18
  setError(null);
59
19
  try {
60
- const data = await client.fetchPermissions(uid);
61
- const normalizedRoles = data.roles.map((role)=>'string' == typeof role ? role : role.name);
62
- setPermissions(data.permissions);
63
- setRoles(normalizedRoles);
64
- setUserId(data.userId);
20
+ const data = await client.fetchPermissions();
65
21
  updateAbility(ability, {
66
- permissions: data.permissions,
67
- roles: normalizedRoles
22
+ roles: data.roles
68
23
  });
69
24
  config?.onSuccess?.(data);
70
25
  } catch (err) {
@@ -79,28 +34,17 @@ function AuthProvider({ children, config }) {
79
34
  client,
80
35
  config
81
36
  ]);
82
- const refetch = useCallback(async ()=>{
83
- await fetchPermissions(userId);
84
- }, [
85
- userId,
86
- fetchPermissions
87
- ]);
88
37
  useEffect(()=>{
89
- if (config?.autoFetch !== false) fetchPermissions();
38
+ if (config?.enable !== false) fetchPermissions();
90
39
  }, [
91
- config?.autoFetch,
40
+ config?.enable,
92
41
  fetchPermissions
93
42
  ]);
94
43
  const stateContextValue = {
95
- permissions,
96
- roles,
97
- userId,
98
- setUserId,
99
- noPermissionPath: config?.noPermissionPath,
44
+ ability,
100
45
  isLoading,
101
46
  error,
102
- fetchPermissions,
103
- refetch
47
+ fetchPermissions
104
48
  };
105
49
  return /*#__PURE__*/ jsx(AbilityContext.Provider, {
106
50
  value: ability,
@@ -115,26 +59,13 @@ function useAuth() {
115
59
  if (!context) throw new Error('useAuth must be used within an AuthProvider');
116
60
  return context;
117
61
  }
118
- function useAbility() {
62
+ function useAuthAbility() {
119
63
  return useContext(AbilityContext);
120
64
  }
121
- function usePermissions() {
122
- const { permissions } = useAuth();
123
- return permissions;
124
- }
125
- function useRoles() {
126
- const { roles } = useAuth();
127
- return roles;
128
- }
129
- function useUserId() {
130
- const { userId, setUserId } = useAuth();
131
- return [
132
- userId,
133
- setUserId
134
- ];
135
- }
136
- function useNoPermissionPath() {
137
- const { noPermissionPath } = useAuth();
138
- return noPermissionPath;
139
- }
140
- export { AbilityContext, AuthProvider, Can, CanPermission, CanRole, useAbility, useAuth, useCanPermission, useCanRole, useNoPermissionPath, usePermissions, useRoles, useUserId };
65
+ const Can = createContextualCan(AbilityContext.Consumer);
66
+ const CanRole = ({ children, I })=>/*#__PURE__*/ jsx(Can, {
67
+ I: I,
68
+ a: ROLE_SUBJECT,
69
+ children: children
70
+ });
71
+ export { AbilityContext, AuthProvider, Can, CanRole, useAuth, useAuthAbility };
@@ -1,4 +1,4 @@
1
- import { Ability } from '@casl/ability';
1
+ import { MongoAbility as Ability } from '@casl/ability';
2
2
  import type { Permission, CaslRule } from './types';
3
3
  export declare const ROLE_SUBJECT = "@role";
4
4
  /**
@@ -6,9 +6,9 @@ export declare const ROLE_SUBJECT = "@role";
6
6
  */
7
7
  export declare function convertPermissionsToRules(permissions: Permission[], roles: string[]): CaslRule[];
8
8
  /**
9
- * 创建 Ability 实例
9
+ * 创建 MongoAbility 实例
10
10
  */
11
- export declare function createAbility({ permissions, roles }: {
11
+ export declare function createAbility({ permissions, roles, }: {
12
12
  permissions?: Permission[];
13
13
  roles?: string[];
14
14
  }): Ability;
@@ -1 +1 @@
1
- {"version":3,"file":"ability-factory.d.ts","sourceRoot":"","sources":["../src/ability-factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAgC,MAAM,eAAe,CAAC;AACtE,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEpD,eAAO,MAAM,YAAY,UAAU,CAAC;AACpC;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,WAAW,EAAE,UAAU,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,CAoBhG;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,EAAC,WAAW,EAAE,KAAK,EAAC,EAAE;IAAC,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;CAAC,GAAG,OAAO,CAkB3G;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,EAAC,WAAW,EAAE,KAAK,EAAC,EAAE;IAAC,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;CAAC,GAAG,IAAI,CAG1H"}
1
+ {"version":3,"file":"ability-factory.d.ts","sourceRoot":"","sources":["../src/ability-factory.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,IAAI,OAAO,EAGxB,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEpD,eAAO,MAAM,YAAY,UAAU,CAAC;AACpC;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,WAAW,EAAE,UAAU,EAAE,EACzB,KAAK,EAAE,MAAM,EAAE,GACd,QAAQ,EAAE,CAmBZ;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,EAC5B,WAAW,EACX,KAAK,GACN,EAAE;IACD,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;CAClB,GAAG,OAAO,CAkBV;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,OAAO,EAChB,EAAE,WAAW,EAAE,KAAK,EAAE,EAAE;IAAE,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,GACvE,IAAI,CAGN"}
@@ -1,4 +1,4 @@
1
- import { Ability, AbilityBuilder } from "@casl/ability";
1
+ import { AbilityBuilder, createMongoAbility } from "@casl/ability";
2
2
  const ROLE_SUBJECT = '@role';
3
3
  function convertPermissionsToRules(permissions, roles) {
4
4
  const rules = [];
@@ -13,7 +13,7 @@ function convertPermissionsToRules(permissions, roles) {
13
13
  return rules;
14
14
  }
15
15
  function createAbility({ permissions, roles }) {
16
- const { build, can } = new AbilityBuilder(Ability);
16
+ const { build, can } = new AbilityBuilder(createMongoAbility);
17
17
  const rules = convertPermissionsToRules(permissions || [], roles || []);
18
18
  for (const rule of rules)if (Array.isArray(rule.action)) for (const action of rule.action)can(action, rule.subject, rule.fields);
19
19
  else can(rule.action, rule.subject, rule.fields);
package/lib/index.d.ts CHANGED
@@ -5,11 +5,9 @@
5
5
  * 封装了权限数据获取和 Ability 初始化逻辑
6
6
  */
7
7
  export type { Action, Subject, Permission, UserRole, PermissionApiResponse, PermissionApiConfig, AuthSdkConfig, CaslRule, } from './types';
8
- export { createAbility, updateAbility, convertPermissionsToRules, } from './ability-factory';
8
+ export { createAbility, updateAbility, convertPermissionsToRules, ROLE_SUBJECT, } from './ability-factory';
9
9
  export { PermissionClient } from './permission-client';
10
- export { AuthProvider, Can, useCanPermission, CanPermission, useCanRole, CanRole, useAuth, useAbility, usePermissions, useRoles, AbilityContext, useUserId, useNoPermissionPath, } from './AuthProvider';
11
- export { CanRoute } from './CanRoute';
12
- export type { AuthProviderProps, UseCanPermissionProps, UseCanRoleProps, CanPermissionProps, CanRoleProps, } from './AuthProvider';
13
- export type { CanRouteProps } from './CanRoute';
14
- export { Ability, AbilityBuilder, type AbilityClass } from '@casl/ability';
10
+ export { AuthProvider, useAuth, useAuthAbility, Can, AbilityContext, } from './AuthProvider';
11
+ export type { AuthProviderProps } from './AuthProvider';
12
+ export { MongoAbility, AbilityBuilder, type AbilityClass } from '@casl/ability';
15
13
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,YAAY,EACV,MAAM,EACN,OAAO,EACP,UAAU,EACV,QAAQ,EACR,qBAAqB,EACrB,mBAAmB,EACnB,aAAa,EACb,QAAQ,GACT,MAAM,SAAS,CAAC;AAGjB,OAAO,EACL,aAAa,EACb,aAAa,EACb,yBAAyB,GAC1B,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAGvD,OAAO,EACL,YAAY,EACZ,GAAG,EACH,gBAAgB,EAChB,aAAa,EACb,UAAU,EACV,OAAO,EACP,OAAO,EACP,UAAU,EACV,cAAc,EACd,QAAQ,EACR,cAAc,EACd,SAAS,EACT,mBAAmB,GACpB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,YAAY,EACV,iBAAiB,EACjB,qBAAqB,EACrB,eAAe,EACf,kBAAkB,EAClB,YAAY,GACb,MAAM,gBAAgB,CAAC;AAExB,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAGhD,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,YAAY,EACV,MAAM,EACN,OAAO,EACP,UAAU,EACV,QAAQ,EACR,qBAAqB,EACrB,mBAAmB,EACnB,aAAa,EACb,QAAQ,GACT,MAAM,SAAS,CAAC;AAGjB,OAAO,EACL,aAAa,EACb,aAAa,EACb,yBAAyB,EACzB,YAAY,GACb,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAGvD,OAAO,EACL,YAAY,EACZ,OAAO,EACP,cAAc,EACd,GAAG,EACH,cAAc,GACf,MAAM,gBAAgB,CAAC;AAExB,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAGxD,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC"}
package/lib/index.js CHANGED
@@ -1,6 +1,5 @@
1
- import { convertPermissionsToRules, createAbility, updateAbility } from "./ability-factory.js";
1
+ import { ROLE_SUBJECT, convertPermissionsToRules, createAbility, updateAbility } from "./ability-factory.js";
2
2
  import { PermissionClient } from "./permission-client.js";
3
- import { AbilityContext, AuthProvider, Can, CanPermission, CanRole, useAbility, useAuth, useCanPermission, useCanRole, useNoPermissionPath, usePermissions, useRoles, useUserId } from "./AuthProvider.js";
4
- import { CanRoute } from "./CanRoute.js";
5
- import { Ability, AbilityBuilder } from "@casl/ability";
6
- export { Ability, AbilityBuilder, AbilityContext, AuthProvider, Can, CanPermission, CanRole, CanRoute, PermissionClient, convertPermissionsToRules, createAbility, updateAbility, useAbility, useAuth, useCanPermission, useCanRole, useNoPermissionPath, usePermissions, useRoles, useUserId };
3
+ import { AbilityContext, AuthProvider, Can, useAuth, useAuthAbility } from "./AuthProvider.js";
4
+ import { AbilityBuilder, MongoAbility } from "@casl/ability";
5
+ export { AbilityBuilder, AbilityContext, AuthProvider, Can, MongoAbility, PermissionClient, ROLE_SUBJECT, convertPermissionsToRules, createAbility, updateAbility, useAuth, useAuthAbility };
@@ -7,9 +7,8 @@ export declare class PermissionClient {
7
7
  constructor(config?: PermissionApiConfig);
8
8
  /**
9
9
  * 获取用户权限数据
10
- * @param userId - 用户ID(可选,用于向后兼容。如果端点包含 :userId,则会替换)
11
10
  */
12
- fetchPermissions(userId?: string): Promise<PermissionApiResponse>;
11
+ fetchPermissions(): Promise<PermissionApiResponse>;
13
12
  /**
14
13
  * 更新配置
15
14
  */
@@ -1 +1 @@
1
- {"version":3,"file":"permission-client.d.ts","sourceRoot":"","sources":["../src/permission-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAY1E;;GAEG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAsB;gBAExB,MAAM,CAAC,EAAE,mBAAmB;IAOxC;;;OAGG;IACG,gBAAgB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAsEvE;;OAEG;IACH,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,mBAAmB,CAAC,GAAG,IAAI;IAOxD;;OAEG;IACH,SAAS,IAAI,mBAAmB;CAGjC"}
1
+ {"version":3,"file":"permission-client.d.ts","sourceRoot":"","sources":["../src/permission-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAU1E;;GAEG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAsB;gBAExB,MAAM,CAAC,EAAE,mBAAmB;IAOxC;;OAEG;IACG,gBAAgB,IAAI,OAAO,CAAC,qBAAqB,CAAC;IAyDxD;;OAEG;IACH,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,mBAAmB,CAAC,GAAG,IAAI;IAOxD;;OAEG;IACH,SAAS,IAAI,mBAAmB;CAGjC"}
@@ -1,8 +1,6 @@
1
1
  const DEFAULT_CONFIG = {
2
2
  baseUrl: '',
3
- endpoint: '/api/permissions',
4
- timeout: 5000,
5
- withCredentials: true
3
+ timeout: 5000
6
4
  };
7
5
  class PermissionClient {
8
6
  constructor(config){
@@ -11,16 +9,15 @@ class PermissionClient {
11
9
  ...config
12
10
  };
13
11
  }
14
- async fetchPermissions(userId) {
15
- const { baseUrl = DEFAULT_CONFIG.baseUrl, endpoint = DEFAULT_CONFIG.endpoint, timeout = DEFAULT_CONFIG.timeout, headers = {}, apiToken, withCredentials = DEFAULT_CONFIG.withCredentials } = this.config;
16
- let finalEndpoint = endpoint;
17
- if (userId) finalEndpoint = endpoint.includes(':userId') ? endpoint.replace(':userId', userId) : `${endpoint}?mockUserId=${userId}`;
18
- const url = `${baseUrl}${finalEndpoint}`;
12
+ async fetchPermissions() {
13
+ const { timeout = DEFAULT_CONFIG.timeout, headers = {} } = this.config;
14
+ const { appId } = window;
15
+ if (!appId) throw new Error('appId is required');
16
+ const url = `/app/${appId}/runtime/api/v1/permissions/roles`;
19
17
  const requestHeaders = {
20
18
  'Content-Type': 'application/json',
21
19
  ...headers
22
20
  };
23
- if (apiToken) requestHeaders['Authorization'] = `Bearer ${apiToken}`;
24
21
  const controller = new AbortController();
25
22
  const timeoutId = setTimeout(()=>controller.abort(), timeout);
26
23
  try {
@@ -28,18 +25,18 @@ class PermissionClient {
28
25
  method: 'GET',
29
26
  headers: requestHeaders,
30
27
  signal: controller.signal,
31
- credentials: withCredentials ? 'include' : 'same-origin'
28
+ credentials: 'include'
32
29
  });
33
30
  clearTimeout(timeoutId);
34
31
  if (!response.ok) throw new Error(`Permission API returned ${response.status}: ${response.statusText}`);
35
32
  const data = await response.json();
36
33
  return {
37
- ...data,
38
- fetchedAt: data.fetchedAt || new Date().toISOString()
34
+ roles: data.data?.role_list || [],
35
+ fetchedAt: new Date()
39
36
  };
40
37
  } catch (error) {
41
38
  clearTimeout(timeoutId);
42
- if ('AbortError' === error.name) throw new Error(`Permission API request timeout after ${timeout}ms`);
39
+ if (error instanceof Error && 'AbortError' === error.name) throw new Error(`Permission API request timeout after ${timeout}ms`);
43
40
  throw error;
44
41
  }
45
42
  }
package/lib/types.d.ts CHANGED
@@ -27,9 +27,7 @@ export interface UserRole {
27
27
  * 权限 API 响应数据
28
28
  */
29
29
  export interface PermissionApiResponse {
30
- userId: string;
31
- roles: (string | UserRole)[];
32
- permissions: Permission[];
30
+ roles: string[];
33
31
  fetchedAt?: string | Date;
34
32
  }
35
33
  /**
@@ -41,11 +39,6 @@ export interface PermissionApiConfig {
41
39
  * @default ''
42
40
  */
43
41
  baseUrl?: string;
44
- /**
45
- * API 端点路径
46
- * @default '/api/permissions'
47
- */
48
- endpoint?: string;
49
42
  /**
50
43
  * 请求超时时间(毫秒)
51
44
  * @default 5000
@@ -55,34 +48,20 @@ export interface PermissionApiConfig {
55
48
  * 自定义请求头
56
49
  */
57
50
  headers?: Record<string, string>;
58
- /**
59
- * API Token,会自动添加到 Authorization header
60
- */
61
- apiToken?: string;
62
- /**
63
- * 是否携带凭证(cookies)
64
- * @default true
65
- */
66
- withCredentials?: boolean;
67
51
  }
68
52
  /**
69
53
  * Auth SDK 配置选项
70
54
  */
71
55
  export interface AuthSdkConfig {
72
- /**
73
- * 无权限路径
74
- * @default '/no-access'
75
- */
76
- noPermissionPath?: string;
77
56
  /**
78
57
  * 权限 API 配置
79
58
  */
80
59
  permissionApi?: PermissionApiConfig;
81
60
  /**
82
- * 是否在初始化时自动获取权限
61
+ * 是否在初始化时使用获取权限
83
62
  * @default false
84
63
  */
85
- autoFetch?: boolean;
64
+ enable?: boolean;
86
65
  /**
87
66
  * 获取权限失败时的错误处理
88
67
  */
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,MAAM,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEjF;;GAEG;AACH,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC;AAE7B;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,OAAO,CAAC;IACb,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,CAAC,MAAM,GAAG,QAAQ,CAAC,EAAE,CAAC;IAC7B,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEjC;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B;;OAEG;IACH,aAAa,CAAC,EAAE,mBAAmB,CAAC;IAEpC;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAEjC;;OAEG;IACH,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,qBAAqB,KAAK,IAAI,CAAC;CACnD;AAED;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC1B,OAAO,EAAE,OAAO,GAAG,OAAO,EAAE,CAAC;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,MAAM,GACd,QAAQ,GACR,MAAM,GACN,QAAQ,GACR,QAAQ,GACR,QAAQ,GACR,MAAM,CAAC;AAEX;;GAEG;AACH,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC;AAE7B;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,OAAO,CAAC;IACb,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;OAEG;IACH,aAAa,CAAC,EAAE,mBAAmB,CAAC;IAEpC;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAEjC;;OAEG;IACH,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,qBAAqB,KAAK,IAAI,CAAC;CACnD;AAED;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC1B,OAAO,EAAE,OAAO,GAAG,OAAO,EAAE,CAAC;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lark-apaas/auth-sdk",
3
- "version": "0.1.0-alpha.0",
3
+ "version": "0.1.0-alpha.4",
4
4
  "description": "基于 CASL 的前端鉴权 SDK",
5
5
  "types": "./lib/index.d.ts",
6
6
  "main": "./lib/index.js",
package/lib/CanRoute.d.ts DELETED
@@ -1,42 +0,0 @@
1
- import { type ReactNode } from 'react';
2
- /**
3
- * CanRoute 组件 Props
4
- */
5
- export interface CanRouteProps {
6
- permissions?: Array<{
7
- action: string;
8
- subject: string;
9
- }>;
10
- roles?: string[];
11
- children: ReactNode;
12
- redirectTo?: string;
13
- fallback?: ReactNode;
14
- }
15
- /**
16
- * CanRoute 组件 - 路由级别的权限守卫
17
- *
18
- * 基于权限和角色进行路由级别的访问控制
19
- * 当权限或角色检查失败时,会渲染 fallback 内容或返回 null
20
- *
21
- * @example
22
- * ```tsx
23
- * import { CanRoute } from '@lark-apaas/auth-sdk';
24
- * import { Navigate, useLocation } from 'react-router-dom';
25
- *
26
- * function ProtectedRoute() {
27
- * const location = useLocation();
28
- *
29
- * return (
30
- * <CanRoute
31
- * permissions={[{ action: 'read', subject: 'Task' }]}
32
- * roles={['admin']}
33
- * fallback={<Navigate to="/forbidden" replace state={{ from: location }} />}
34
- * >
35
- * <TaskList />
36
- * </CanRoute>
37
- * );
38
- * }
39
- * ```
40
- */
41
- export declare function CanRoute({ permissions, roles, children, fallback, redirectTo }: CanRouteProps): import("react/jsx-runtime").JSX.Element | null;
42
- //# sourceMappingURL=CanRoute.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"CanRoute.d.ts","sourceRoot":"","sources":["../src/CanRoute.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAItC;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,WAAW,CAAC,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACzD,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,SAAS,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,QAAQ,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAe,EAAE,UAAe,EAAE,EAAE,aAAa,kDAezG"}
package/lib/CanRoute.js DELETED
@@ -1,27 +0,0 @@
1
- import { Fragment, jsx } from "react/jsx-runtime";
2
- import { Navigate, useLocation } from "react-router-dom";
3
- import { useCanPermission, useCanRole, useNoPermissionPath } from "./AuthProvider.js";
4
- function CanRoute({ permissions, roles, children, fallback = null, redirectTo = '' }) {
5
- const noPermissionPath = useNoPermissionPath();
6
- const location = useLocation();
7
- let allPass = true;
8
- if (!useCanPermission({
9
- permissions
10
- })) allPass = false;
11
- if (!useCanRole({
12
- roles
13
- })) allPass = false;
14
- if (!allPass) return fallback ? /*#__PURE__*/ jsx(Fragment, {
15
- children: fallback
16
- }) : redirectTo || noPermissionPath ? /*#__PURE__*/ jsx(Navigate, {
17
- to: redirectTo || noPermissionPath,
18
- replace: true,
19
- state: {
20
- from: location
21
- }
22
- }) : null;
23
- return /*#__PURE__*/ jsx(Fragment, {
24
- children: children
25
- });
26
- }
27
- export { CanRoute };
@@ -1,42 +0,0 @@
1
- import { type ReactNode } from 'react';
2
- /**
3
- * RouteGuard 组件 Props
4
- */
5
- export interface RouteGuardProps {
6
- permissions?: Array<{
7
- action: string;
8
- subject: string;
9
- }>;
10
- roles?: string[];
11
- children: ReactNode;
12
- redirectTo?: string;
13
- fallback?: ReactNode;
14
- }
15
- /**
16
- * RouteGuard 组件 - 路由级别的权限守卫
17
- *
18
- * 基于权限和角色进行路由级别的访问控制
19
- * 当权限或角色检查失败时,会渲染 fallback 内容或返回 null
20
- *
21
- * @example
22
- * ```tsx
23
- * import { RouteGuard } from '@lark-apaas/auth-sdk';
24
- * import { Navigate, useLocation } from 'react-router-dom';
25
- *
26
- * function ProtectedRoute() {
27
- * const location = useLocation();
28
- *
29
- * return (
30
- * <RouteGuard
31
- * permissions={[{ action: 'read', subject: 'Task' }]}
32
- * roles={['admin']}
33
- * fallback={<Navigate to="/forbidden" replace state={{ from: location }} />}
34
- * >
35
- * <TaskList />
36
- * </RouteGuard>
37
- * );
38
- * }
39
- * ```
40
- */
41
- export declare function RouteGuard({ permissions, roles, children, fallback, redirectTo }: RouteGuardProps): import("react/jsx-runtime").JSX.Element | null;
42
- //# sourceMappingURL=RouteGuard.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"RouteGuard.d.ts","sourceRoot":"","sources":["../src/RouteGuard.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAGtC;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,WAAW,CAAC,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACzD,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,SAAS,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,UAAU,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAe,EAAE,UAAe,EAAE,EAAE,eAAe,kDAe7G"}
package/lib/RouteGuard.js DELETED
@@ -1,27 +0,0 @@
1
- import { Fragment, jsx } from "react/jsx-runtime";
2
- import { Navigate, useLocation } from "react-router-dom";
3
- import { useCanPermission, useCanRole, useNoPermissionPath } from "./AuthProvider.js";
4
- function RouteGuard({ permissions, roles, children, fallback = null, redirectTo = '' }) {
5
- const noPermissionPath = useNoPermissionPath();
6
- const location = useLocation();
7
- let allPass = true;
8
- if (!useCanPermission({
9
- permissions
10
- })) allPass = false;
11
- if (!useCanRole({
12
- roles
13
- })) allPass = false;
14
- if (!allPass) return fallback ? /*#__PURE__*/ jsx(Fragment, {
15
- children: fallback
16
- }) : redirectTo || noPermissionPath ? /*#__PURE__*/ jsx(Navigate, {
17
- to: redirectTo || noPermissionPath,
18
- replace: true,
19
- state: {
20
- from: location
21
- }
22
- }) : null;
23
- return /*#__PURE__*/ jsx(Fragment, {
24
- children: children
25
- });
26
- }
27
- export { RouteGuard };