@lark-apaas/auth-sdk 0.1.0-alpha.8 → 0.1.0-alpha.81
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 +4 -27
- package/lib/AuthProvider.d.ts +49 -48
- package/lib/AuthProvider.d.ts.map +1 -1
- package/lib/AuthProvider.js +64 -42
- package/lib/ability-factory.d.ts +7 -7
- package/lib/ability-factory.d.ts.map +1 -1
- package/lib/ability-factory.js +9 -9
- package/lib/index.d.ts +2 -2
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2 -2
- package/lib/permission-client.d.ts +1 -1
- package/lib/permission-client.d.ts.map +1 -1
- package/lib/permission-client.js +16 -14
- package/lib/types.d.ts +20 -9
- package/lib/types.d.ts.map +1 -1
- package/package.json +6 -4
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@ yarn add @lark-apaas/auth-sdk
|
|
|
16
16
|
|
|
17
17
|
```tsx
|
|
18
18
|
import React from 'react';
|
|
19
|
-
import { AuthProvider,
|
|
19
|
+
import { AuthProvider, CanRole, useAuth } from '@lark-apaas/auth-sdk';
|
|
20
20
|
|
|
21
21
|
export default function App() {
|
|
22
22
|
return (
|
|
@@ -35,7 +35,8 @@ export default function App() {
|
|
|
35
35
|
}
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
|
|
39
|
+
### 开发组件 - 使用 CanRole 组件
|
|
39
40
|
|
|
40
41
|
```tsx
|
|
41
42
|
import { CanRole } from '@lark-apaas/auth-sdk';
|
|
@@ -72,31 +73,7 @@ function Home() {
|
|
|
72
73
|
}
|
|
73
74
|
```
|
|
74
75
|
|
|
75
|
-
### 开发组件 -
|
|
76
|
-
|
|
77
|
-
### 菜单按权限过滤
|
|
78
|
-
|
|
79
|
-
```tsx
|
|
80
|
-
import { useContext } from 'react';
|
|
81
|
-
import { AbilityContext } from '@lark-apaas/auth-sdk';
|
|
82
|
-
|
|
83
|
-
const menus = [
|
|
84
|
-
{ name: 'Dashboard', path: '/dashboard', p: { action: 'role_admin', subject: '@role' } },
|
|
85
|
-
{ name: 'Users', path: '/users', p: { action: 'role_editor', subject: '@role' } },
|
|
86
|
-
{ name: 'Settings', path: '/settings', p: { action: 'role_admin', subject: '@role' } },
|
|
87
|
-
];
|
|
88
|
-
|
|
89
|
-
function Nav() {
|
|
90
|
-
const ability = useContext(AbilityContext);
|
|
91
|
-
return (
|
|
92
|
-
<nav>
|
|
93
|
-
{menus.map(m => ability.can(m.p.action, m.p.subject) && (
|
|
94
|
-
<a key={m.path} href={m.path}>{m.name}</a>
|
|
95
|
-
))}
|
|
96
|
-
</nav>
|
|
97
|
-
);
|
|
98
|
-
}
|
|
99
|
-
```
|
|
76
|
+
### 开发组件 - 见 Client Toolkit
|
|
100
77
|
|
|
101
78
|
---
|
|
102
79
|
|
package/lib/AuthProvider.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { MongoAbility } from '@casl/ability';
|
|
3
|
-
import type { AuthSdkConfig } from './types';
|
|
3
|
+
import type { AuthSdkConfig, PermissionPointData } from './types';
|
|
4
4
|
/**
|
|
5
5
|
* Ability Context - 用于在组件树中共享 Ability 实例
|
|
6
6
|
*/
|
|
@@ -11,6 +11,7 @@ export declare const AbilityContext: React.Context<MongoAbility<import("@casl/ab
|
|
|
11
11
|
*/
|
|
12
12
|
interface AuthStateContextValue {
|
|
13
13
|
ability: MongoAbility;
|
|
14
|
+
permissions: PermissionPointData[];
|
|
14
15
|
isLoading: boolean;
|
|
15
16
|
error: Error | null;
|
|
16
17
|
fetchPermissions: (userId?: string) => Promise<void>;
|
|
@@ -33,10 +34,9 @@ export interface AuthProviderProps {
|
|
|
33
34
|
*
|
|
34
35
|
* function App() {
|
|
35
36
|
* return (
|
|
36
|
-
* <AuthProvider
|
|
37
|
+
* <AuthProvider config={{
|
|
37
38
|
* permissionApi: {
|
|
38
|
-
*
|
|
39
|
-
* endpoint: '/mock-api/users/:userId/permissions'
|
|
39
|
+
* url: '/app/app_xxx/__runtime__/api/v1/permissions/roles',
|
|
40
40
|
* }
|
|
41
41
|
* }}>
|
|
42
42
|
* <YourApp />
|
|
@@ -46,23 +46,15 @@ export interface AuthProviderProps {
|
|
|
46
46
|
* ```
|
|
47
47
|
*/
|
|
48
48
|
export declare function AuthProvider({ children, config }: AuthProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
49
|
-
/**
|
|
50
|
-
* 获取 Ability 实例
|
|
51
|
-
*
|
|
52
|
-
* @param permissionApiConfig - 权限 API 配置
|
|
53
|
-
* @returns Ability 实例或错误
|
|
54
|
-
*/
|
|
55
|
-
export declare function getAbility(permissionApiConfig: AuthSdkConfig['permissionApi']): Promise<Error | MongoAbility<import("@casl/ability").AbilityTuple, import("@casl/ability").MongoQuery>>;
|
|
56
49
|
/**
|
|
57
50
|
* useAuth Hook - 获取权限数据和加载状态
|
|
58
51
|
*
|
|
59
52
|
* @example
|
|
60
53
|
* ```tsx
|
|
61
|
-
* import { useAuth
|
|
54
|
+
* import { useAuth } from '@lark-apaas/auth-sdk';
|
|
62
55
|
*
|
|
63
56
|
* function MyComponent() {
|
|
64
|
-
* const {
|
|
65
|
-
* const ability = useAbility();
|
|
57
|
+
* const { ability, isLoading } = useAuth();
|
|
66
58
|
*
|
|
67
59
|
* if (isLoading) return <div>Loading...</div>;
|
|
68
60
|
*
|
|
@@ -76,63 +68,72 @@ export declare function getAbility(permissionApiConfig: AuthSdkConfig['permissio
|
|
|
76
68
|
*/
|
|
77
69
|
export declare function useAuth(): AuthStateContextValue;
|
|
78
70
|
/**
|
|
79
|
-
*
|
|
71
|
+
* CanRole Component - 基于角色的条件渲染组件
|
|
72
|
+
*
|
|
73
|
+
* 支持 fallback prop,用于在权限加载期间显示自定义内容(如 Loading),
|
|
74
|
+
* 避免加载期间因 can() 返回 false 而误判为无权限。
|
|
80
75
|
*
|
|
81
76
|
* @example
|
|
82
77
|
* ```tsx
|
|
83
|
-
* import {
|
|
78
|
+
* import { CanRole } from '@lark-apaas/auth-sdk';
|
|
84
79
|
*
|
|
85
80
|
* function MyComponent() {
|
|
86
|
-
* const ability = useAuthAbility();
|
|
87
|
-
*
|
|
88
81
|
* return (
|
|
89
|
-
* <
|
|
90
|
-
*
|
|
91
|
-
* </
|
|
82
|
+
* <CanRole roles={['admin']} fallback={<Loading />}>
|
|
83
|
+
* <AdminPanel />
|
|
84
|
+
* </CanRole>
|
|
92
85
|
* );
|
|
93
86
|
* }
|
|
94
87
|
* ```
|
|
95
88
|
*/
|
|
96
|
-
export declare function
|
|
89
|
+
export declare function CanRole({ children, roles, fallback, }: {
|
|
90
|
+
children: React.ReactNode;
|
|
91
|
+
roles: string[];
|
|
92
|
+
fallback?: React.ReactNode;
|
|
93
|
+
}): import("react/jsx-runtime").JSX.Element | null;
|
|
94
|
+
/**
|
|
95
|
+
* useUserPermissions Hook - 获取当前用户的权限点位列表
|
|
96
|
+
*/
|
|
97
|
+
export declare function useUserPermissions(): PermissionPointData[];
|
|
97
98
|
/**
|
|
98
|
-
*
|
|
99
|
+
* useCan Hook - 通过 CASL Ability 判断用户是否拥有指定权限
|
|
99
100
|
*
|
|
100
|
-
* @
|
|
101
|
-
*
|
|
102
|
-
* import { Can } from '@lark-apaas/auth-sdk';
|
|
101
|
+
* @param action - 操作类型,如 'read', 'create'
|
|
102
|
+
* @param subject - 资源类型,如 'Task', 'Article';角色检查时传 '@role'
|
|
103
103
|
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
* );
|
|
110
|
-
* }
|
|
104
|
+
* @example
|
|
105
|
+
* ```ts
|
|
106
|
+
* const { allowed: canRead, isLoading } = useCan('read', 'Task');
|
|
107
|
+
* if (isLoading) return <Loading />;
|
|
108
|
+
* if (!canRead) return <NoAccess />;
|
|
111
109
|
* ```
|
|
112
110
|
*/
|
|
113
|
-
export declare
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}
|
|
111
|
+
export declare function useCan(action: string, subject: string): {
|
|
112
|
+
allowed: boolean;
|
|
113
|
+
isLoading: boolean;
|
|
114
|
+
};
|
|
117
115
|
/**
|
|
118
|
-
*
|
|
116
|
+
* Can Component - 基于 CASL Ability 的条件渲染组件
|
|
117
|
+
* 前后端统一:后端 @Can('read', 'Task'),前端 <Can action="read" subject="Task">
|
|
119
118
|
*
|
|
120
119
|
* @example
|
|
121
120
|
* ```tsx
|
|
122
|
-
* import {
|
|
121
|
+
* import { Can } from '@lark-apaas/auth-sdk';
|
|
123
122
|
*
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
*
|
|
123
|
+
* <Can action="read" subject="Task">
|
|
124
|
+
* <TaskList />
|
|
125
|
+
* </Can>
|
|
126
|
+
*
|
|
127
|
+
* <Can action="delete" subject="Task" fallback={<Skeleton />}>
|
|
128
|
+
* <DeleteButton />
|
|
129
|
+
* </Can>
|
|
131
130
|
* ```
|
|
132
131
|
*/
|
|
133
|
-
export declare function
|
|
132
|
+
export declare function Can({ children, action, subject, fallback, }: {
|
|
134
133
|
children: React.ReactNode;
|
|
135
|
-
|
|
134
|
+
action: string;
|
|
135
|
+
subject: string;
|
|
136
|
+
fallback?: React.ReactNode;
|
|
136
137
|
}): import("react/jsx-runtime").JSX.Element | null;
|
|
137
138
|
export {};
|
|
138
139
|
//# sourceMappingURL=AuthProvider.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
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;
|
|
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,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAIlE;;GAEG;AACH,eAAO,MAAM,cAAc,uGAE1B,CAAC;AAOF;;;GAGG;AACH,UAAU,qBAAqB;IAC7B,OAAO,EAAE,YAAY,CAAC;IACtB,WAAW,EAAE,mBAAmB,EAAE,CAAC;IACnC,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;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,YAAY,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,iBAAiB,2CAkFnE;AAGD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,OAAO,IAAI,qBAAqB,CAQ/C;AAqBD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,OAAO,CAAC,EACtB,QAAQ,EACR,KAAK,EACL,QAAe,GAChB,EAAE;IACD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B,kDAKA;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,mBAAmB,EAAE,CAE1D;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,MAAM,CACpB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,GACd;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAM1C;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,GAAG,CAAC,EAClB,QAAQ,EACR,MAAM,EACN,OAAO,EACP,QAAe,GAChB,EAAE;IACD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B,kDAIA"}
|
package/lib/AuthProvider.js
CHANGED
|
@@ -1,27 +1,37 @@
|
|
|
1
1
|
import { Fragment, jsx } from "react/jsx-runtime";
|
|
2
2
|
import { createContext, useCallback, useContext, useEffect, useState } from "react";
|
|
3
|
-
import { ROLE_SUBJECT, createAbility
|
|
3
|
+
import { ROLE_SUBJECT, createAbility } from "./ability-factory.js";
|
|
4
4
|
import { PermissionClient } from "./permission-client.js";
|
|
5
|
-
import { createContextualCan } from "@casl/react";
|
|
6
5
|
const AbilityContext = /*#__PURE__*/ createContext(createAbility({
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
roles: [],
|
|
7
|
+
permissionPoints: []
|
|
9
8
|
}));
|
|
9
|
+
const PermissionsContext = /*#__PURE__*/ createContext([]);
|
|
10
10
|
const AuthStateContext = /*#__PURE__*/ createContext(null);
|
|
11
11
|
function AuthProvider({ children, config }) {
|
|
12
|
-
const [ability] = useState(()=>createAbility({}));
|
|
13
|
-
const [
|
|
12
|
+
const [ability, setAbility] = useState(()=>createAbility({}));
|
|
13
|
+
const [permissions, setPermissions] = useState([]);
|
|
14
|
+
const [client] = useState(()=>config?.permissionApi ? new PermissionClient(config.permissionApi) : null);
|
|
15
|
+
const [isLoading, setIsLoading] = useState(()=>config?.enable !== false && null !== client);
|
|
14
16
|
const [error, setError] = useState(null);
|
|
15
|
-
const [client] = useState(()=>new PermissionClient(config?.permissionApi));
|
|
16
17
|
const fetchPermissions = useCallback(async ()=>{
|
|
18
|
+
if (!client) return;
|
|
17
19
|
setIsLoading(true);
|
|
18
20
|
setError(null);
|
|
19
21
|
try {
|
|
20
22
|
const data = await client.fetchPermissions();
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
let permissionPoints;
|
|
24
|
+
if (config?.permissionPointsFetcher) try {
|
|
25
|
+
permissionPoints = await config.permissionPointsFetcher();
|
|
26
|
+
setPermissions(permissionPoints);
|
|
27
|
+
} catch {}
|
|
28
|
+
const rawConfig = {
|
|
29
|
+
roles: data.roles,
|
|
30
|
+
permissionPoints
|
|
31
|
+
};
|
|
32
|
+
const newAbility = createAbility(rawConfig);
|
|
33
|
+
setAbility(newAbility);
|
|
34
|
+
config?.onSuccess?.(rawConfig);
|
|
25
35
|
} catch (err) {
|
|
26
36
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
27
37
|
setError(error);
|
|
@@ -30,7 +40,6 @@ function AuthProvider({ children, config }) {
|
|
|
30
40
|
setIsLoading(false);
|
|
31
41
|
}
|
|
32
42
|
}, [
|
|
33
|
-
ability,
|
|
34
43
|
client,
|
|
35
44
|
config
|
|
36
45
|
]);
|
|
@@ -42,54 +51,67 @@ function AuthProvider({ children, config }) {
|
|
|
42
51
|
]);
|
|
43
52
|
const stateContextValue = {
|
|
44
53
|
ability,
|
|
54
|
+
permissions,
|
|
45
55
|
isLoading,
|
|
46
56
|
error,
|
|
47
57
|
fetchPermissions
|
|
48
58
|
};
|
|
49
59
|
return /*#__PURE__*/ jsx(AbilityContext.Provider, {
|
|
50
60
|
value: ability,
|
|
51
|
-
children: /*#__PURE__*/ jsx(
|
|
52
|
-
value:
|
|
53
|
-
children:
|
|
61
|
+
children: /*#__PURE__*/ jsx(PermissionsContext.Provider, {
|
|
62
|
+
value: permissions,
|
|
63
|
+
children: /*#__PURE__*/ jsx(AuthStateContext.Provider, {
|
|
64
|
+
value: stateContextValue,
|
|
65
|
+
children: children
|
|
66
|
+
})
|
|
54
67
|
})
|
|
55
68
|
});
|
|
56
69
|
}
|
|
57
|
-
async function getAbility(permissionApiConfig) {
|
|
58
|
-
const ability = createAbility({});
|
|
59
|
-
const client = new PermissionClient(permissionApiConfig);
|
|
60
|
-
try {
|
|
61
|
-
const data = await client.fetchPermissions();
|
|
62
|
-
updateAbility(ability, {
|
|
63
|
-
roles: data.roles
|
|
64
|
-
});
|
|
65
|
-
} catch (err) {
|
|
66
|
-
const error = err instanceof Error ? err : new Error(String(err));
|
|
67
|
-
return error;
|
|
68
|
-
}
|
|
69
|
-
return ability;
|
|
70
|
-
}
|
|
71
70
|
function useAuth() {
|
|
72
71
|
const context = useContext(AuthStateContext);
|
|
73
72
|
if (!context) throw new Error('useAuth must be used within an AuthProvider');
|
|
74
73
|
return context;
|
|
75
74
|
}
|
|
76
|
-
function
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
const Can = createContextualCan(AbilityContext.Consumer);
|
|
80
|
-
const useCanRole = function({ roles }) {
|
|
81
|
-
const context = useContext(AuthStateContext);
|
|
82
|
-
if (!context) return false;
|
|
83
|
-
const { ability } = context;
|
|
75
|
+
function useCanRole({ roles }) {
|
|
76
|
+
const ability = useContext(AbilityContext);
|
|
77
|
+
const authState = useContext(AuthStateContext);
|
|
84
78
|
const allowed = !roles || 0 === roles.length || roles.length > 0 && roles.some((role)=>ability.can(role, ROLE_SUBJECT));
|
|
85
|
-
return
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
79
|
+
return {
|
|
80
|
+
allowed: !!allowed,
|
|
81
|
+
isLoading: authState?.isLoading ?? false
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
function CanRole({ children, roles, fallback = null }) {
|
|
85
|
+
const { allowed, isLoading } = useCanRole({
|
|
89
86
|
roles
|
|
90
87
|
});
|
|
88
|
+
if (isLoading) return /*#__PURE__*/ jsx(Fragment, {
|
|
89
|
+
children: fallback
|
|
90
|
+
});
|
|
91
|
+
return allowed ? /*#__PURE__*/ jsx(Fragment, {
|
|
92
|
+
children: children
|
|
93
|
+
}) : null;
|
|
94
|
+
}
|
|
95
|
+
function useUserPermissions() {
|
|
96
|
+
return useContext(PermissionsContext);
|
|
97
|
+
}
|
|
98
|
+
function useCan(action, subject) {
|
|
99
|
+
const ability = useContext(AbilityContext);
|
|
100
|
+
const authState = useContext(AuthStateContext);
|
|
101
|
+
const isLoading = authState?.isLoading ?? false;
|
|
102
|
+
const allowed = !isLoading && ability.can(action, subject);
|
|
103
|
+
return {
|
|
104
|
+
allowed,
|
|
105
|
+
isLoading
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function Can({ children, action, subject, fallback = null }) {
|
|
109
|
+
const { allowed, isLoading } = useCan(action, subject);
|
|
110
|
+
if (isLoading) return /*#__PURE__*/ jsx(Fragment, {
|
|
111
|
+
children: fallback
|
|
112
|
+
});
|
|
91
113
|
return allowed ? /*#__PURE__*/ jsx(Fragment, {
|
|
92
114
|
children: children
|
|
93
115
|
}) : null;
|
|
94
116
|
}
|
|
95
|
-
export { AbilityContext, AuthProvider, Can, CanRole,
|
|
117
|
+
export { AbilityContext, AuthProvider, Can, CanRole, useAuth, useCan, useUserPermissions };
|
package/lib/ability-factory.d.ts
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
import { MongoAbility as Ability } from '@casl/ability';
|
|
2
|
-
import type {
|
|
2
|
+
import type { CaslRule, PermissionPointData } from './types';
|
|
3
3
|
export declare const ROLE_SUBJECT = "@role";
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
5
|
+
* 将角色和权限点位转换为 CASL 规则
|
|
6
6
|
*/
|
|
7
|
-
export declare function convertPermissionsToRules(
|
|
7
|
+
export declare function convertPermissionsToRules(roles: string[], permissionPoints?: PermissionPointData[]): CaslRule[];
|
|
8
8
|
/**
|
|
9
9
|
* 创建 MongoAbility 实例
|
|
10
10
|
*/
|
|
11
|
-
export declare function createAbility({
|
|
12
|
-
permissions?: Permission[];
|
|
11
|
+
export declare function createAbility({ roles, permissionPoints, }: {
|
|
13
12
|
roles?: string[];
|
|
13
|
+
permissionPoints?: PermissionPointData[];
|
|
14
14
|
}): Ability;
|
|
15
15
|
/**
|
|
16
16
|
* 更新已存在的 Ability 实例
|
|
17
17
|
*/
|
|
18
|
-
export declare function updateAbility(ability: Ability, {
|
|
19
|
-
permissions?: Permission[];
|
|
18
|
+
export declare function updateAbility(ability: Ability, { roles, permissionPoints }: {
|
|
20
19
|
roles?: string[];
|
|
20
|
+
permissionPoints?: PermissionPointData[];
|
|
21
21
|
}): void;
|
|
22
22
|
//# sourceMappingURL=ability-factory.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
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,
|
|
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,QAAQ,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAE7D,eAAO,MAAM,YAAY,UAAU,CAAC;AACpC;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,MAAM,EAAE,EACf,gBAAgB,CAAC,EAAE,mBAAmB,EAAE,GACvC,QAAQ,EAAE,CAkBZ;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,gBAAgB,GACjB,EAAE;IACD,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,gBAAgB,CAAC,EAAE,mBAAmB,EAAE,CAAC;CAC1C,GAAG,OAAO,CAiBV;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,OAAO,EAChB,EAAE,KAAK,EAAE,gBAAgB,EAAE,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,gBAAgB,CAAC,EAAE,mBAAmB,EAAE,CAAA;CAAE,GAC1F,IAAI,CAGN"}
|
package/lib/ability-factory.js
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
import { AbilityBuilder, createMongoAbility } from "@casl/ability";
|
|
2
2
|
const ROLE_SUBJECT = '@role';
|
|
3
|
-
function convertPermissionsToRules(
|
|
3
|
+
function convertPermissionsToRules(roles, permissionPoints) {
|
|
4
4
|
const rules = [];
|
|
5
|
-
for (const permission of permissions)for (const action of permission.actions)rules.push({
|
|
6
|
-
action,
|
|
7
|
-
subject: permission.sub
|
|
8
|
-
});
|
|
9
5
|
for (const role of roles)rules.push({
|
|
10
6
|
action: role,
|
|
11
7
|
subject: ROLE_SUBJECT
|
|
12
8
|
});
|
|
9
|
+
if (permissionPoints) for (const { action, subject } of permissionPoints)rules.push({
|
|
10
|
+
action,
|
|
11
|
+
subject
|
|
12
|
+
});
|
|
13
13
|
return rules;
|
|
14
14
|
}
|
|
15
|
-
function createAbility({
|
|
15
|
+
function createAbility({ roles, permissionPoints }) {
|
|
16
16
|
const { build, can } = new AbilityBuilder(createMongoAbility);
|
|
17
|
-
const rules = convertPermissionsToRules(
|
|
17
|
+
const rules = convertPermissionsToRules(roles || [], permissionPoints);
|
|
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);
|
|
20
20
|
return build();
|
|
21
21
|
}
|
|
22
|
-
function updateAbility(ability, {
|
|
23
|
-
const rules = convertPermissionsToRules(
|
|
22
|
+
function updateAbility(ability, { roles, permissionPoints }) {
|
|
23
|
+
const rules = convertPermissionsToRules(roles || [], permissionPoints);
|
|
24
24
|
ability.update(rules);
|
|
25
25
|
}
|
|
26
26
|
export { ROLE_SUBJECT, convertPermissionsToRules, createAbility, updateAbility };
|
package/lib/index.d.ts
CHANGED
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
* 基于 CASL 的前端鉴权 SDK
|
|
5
5
|
* 封装了权限数据获取和 Ability 初始化逻辑
|
|
6
6
|
*/
|
|
7
|
-
export type { PermissionApiResponse, PermissionApiConfig, AuthSdkConfig, } from './types';
|
|
7
|
+
export type { PermissionApiResponse, PermissionApiConfig, PermissionPointData, AuthSdkConfig, } from './types';
|
|
8
8
|
export { ROLE_SUBJECT } from './ability-factory';
|
|
9
9
|
export { PermissionClient } from './permission-client';
|
|
10
|
-
export { AuthProvider, useAuth, CanRole, AbilityContext } from './AuthProvider';
|
|
10
|
+
export { AuthProvider, useAuth, Can, CanRole, useCan, AbilityContext, useUserPermissions, } from './AuthProvider';
|
|
11
11
|
export type { AuthProviderProps } from './AuthProvider';
|
|
12
12
|
//# sourceMappingURL=index.d.ts.map
|
package/lib/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,YAAY,EACV,qBAAqB,EACrB,mBAAmB,EACnB,aAAa,GACd,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAGvD,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,YAAY,EACV,qBAAqB,EACrB,mBAAmB,EACnB,mBAAmB,EACnB,aAAa,GACd,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAGvD,OAAO,EACL,YAAY,EACZ,OAAO,EACP,GAAG,EACH,OAAO,EACP,MAAM,EACN,cAAc,EACd,kBAAkB,GACnB,MAAM,gBAAgB,CAAC;AAExB,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC"}
|
package/lib/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { ROLE_SUBJECT } from "./ability-factory.js";
|
|
2
2
|
import { PermissionClient } from "./permission-client.js";
|
|
3
|
-
import { AbilityContext, AuthProvider, CanRole, useAuth } from "./AuthProvider.js";
|
|
4
|
-
export { AbilityContext, AuthProvider, CanRole, PermissionClient, ROLE_SUBJECT, useAuth };
|
|
3
|
+
import { AbilityContext, AuthProvider, Can, CanRole, useAuth, useCan, useUserPermissions } from "./AuthProvider.js";
|
|
4
|
+
export { AbilityContext, AuthProvider, Can, CanRole, PermissionClient, ROLE_SUBJECT, useAuth, useCan, useUserPermissions };
|
|
@@ -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;
|
|
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;AAG1E;;GAEG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAsB;gBAExB,MAAM,EAAE,mBAAmB;IAIvC;;OAEG;IACG,gBAAgB,IAAI,OAAO,CAAC,qBAAqB,CAAC;IAqDxD;;OAEG;IACH,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,mBAAmB,CAAC,GAAG,IAAI;IAOxD;;OAEG;IACH,SAAS,IAAI,mBAAmB;CAGjC"}
|
package/lib/permission-client.js
CHANGED
|
@@ -1,22 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
baseUrl: '',
|
|
3
|
-
timeout: 5000
|
|
4
|
-
};
|
|
1
|
+
import { slardar } from "@lark-apaas/internal-slardar";
|
|
5
2
|
class PermissionClient {
|
|
6
3
|
constructor(config){
|
|
7
|
-
this.config =
|
|
8
|
-
...DEFAULT_CONFIG,
|
|
9
|
-
...config
|
|
10
|
-
};
|
|
4
|
+
this.config = config;
|
|
11
5
|
}
|
|
12
6
|
async fetchPermissions() {
|
|
13
|
-
const { timeout =
|
|
14
|
-
const { appId } = window;
|
|
15
|
-
if (!appId) throw new Error('appId is required');
|
|
16
|
-
const url = `/spark/app/${appId}/runtime/api/v1/permissions/roles`;
|
|
7
|
+
const { url, timeout = 5000, headers = {} } = this.config;
|
|
17
8
|
const requestHeaders = {
|
|
9
|
+
...headers,
|
|
18
10
|
'Content-Type': 'application/json',
|
|
19
|
-
|
|
11
|
+
'X-Suda-Csrf-Token': window.csrfToken || ''
|
|
20
12
|
};
|
|
21
13
|
const controller = new AbortController();
|
|
22
14
|
const timeoutId = setTimeout(()=>controller.abort(), timeout);
|
|
@@ -36,7 +28,17 @@ class PermissionClient {
|
|
|
36
28
|
};
|
|
37
29
|
} catch (error) {
|
|
38
30
|
clearTimeout(timeoutId);
|
|
39
|
-
if (error instanceof Error && 'AbortError' === error.name)
|
|
31
|
+
if (error instanceof Error && 'AbortError' === error.name) {
|
|
32
|
+
slardar.captureException(error, {
|
|
33
|
+
source: 'auth-sdk',
|
|
34
|
+
type: 'timeout'
|
|
35
|
+
});
|
|
36
|
+
throw new Error(`Permission API request timeout after ${timeout}ms`);
|
|
37
|
+
}
|
|
38
|
+
slardar.captureException(error, {
|
|
39
|
+
source: 'auth-sdk',
|
|
40
|
+
type: 'fetch'
|
|
41
|
+
});
|
|
40
42
|
throw error;
|
|
41
43
|
}
|
|
42
44
|
}
|
package/lib/types.d.ts
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
declare global {
|
|
2
|
+
interface Window {
|
|
3
|
+
appId?: string;
|
|
4
|
+
csrfToken?: string;
|
|
5
|
+
userID?: string;
|
|
6
|
+
}
|
|
7
|
+
}
|
|
1
8
|
/**
|
|
2
9
|
* 权限操作类型
|
|
3
10
|
*/
|
|
@@ -7,13 +14,12 @@ export type Action = 'create' | 'read' | 'update' | 'delete' | 'manage' | string
|
|
|
7
14
|
*/
|
|
8
15
|
export type Subject = string;
|
|
9
16
|
/**
|
|
10
|
-
*
|
|
17
|
+
* 权限点位数据(action + subject 分离模式)
|
|
18
|
+
* 由 permissionPointsFetcher 返回,注册到 CASL Ability
|
|
11
19
|
*/
|
|
12
|
-
export interface
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
sub: Subject;
|
|
16
|
-
actions: Action[];
|
|
20
|
+
export interface PermissionPointData {
|
|
21
|
+
action: string;
|
|
22
|
+
subject: string;
|
|
17
23
|
}
|
|
18
24
|
/**
|
|
19
25
|
* 用户角色定义
|
|
@@ -28,6 +34,8 @@ export interface UserRole {
|
|
|
28
34
|
*/
|
|
29
35
|
export interface PermissionApiResponse {
|
|
30
36
|
roles: string[];
|
|
37
|
+
/** 用户的有效权限点位列表 */
|
|
38
|
+
permissions?: string[];
|
|
31
39
|
fetchedAt?: string | Date;
|
|
32
40
|
}
|
|
33
41
|
/**
|
|
@@ -35,10 +43,9 @@ export interface PermissionApiResponse {
|
|
|
35
43
|
*/
|
|
36
44
|
export interface PermissionApiConfig {
|
|
37
45
|
/**
|
|
38
|
-
*
|
|
39
|
-
* @default ''
|
|
46
|
+
* 权限接口完整 URL,由上层注入,不在 SDK 内部硬编码
|
|
40
47
|
*/
|
|
41
|
-
|
|
48
|
+
url: string;
|
|
42
49
|
/**
|
|
43
50
|
* 请求超时时间(毫秒)
|
|
44
51
|
* @default 5000
|
|
@@ -57,6 +64,10 @@ export interface AuthSdkConfig {
|
|
|
57
64
|
* 权限 API 配置
|
|
58
65
|
*/
|
|
59
66
|
permissionApi?: PermissionApiConfig;
|
|
67
|
+
/**
|
|
68
|
+
* 权限点位数据结构(action + subject 分离模式)
|
|
69
|
+
*/
|
|
70
|
+
permissionPointsFetcher?: () => Promise<PermissionPointData[]>;
|
|
60
71
|
/**
|
|
61
72
|
* 是否在初始化时使用获取权限
|
|
62
73
|
* @default false
|
package/lib/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB;CACF;AAED;;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;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;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,kBAAkB;IAClB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;OAEG;IACH,GAAG,EAAE,MAAM,CAAC;IAEZ;;;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;;OAEG;IACH,uBAAuB,CAAC,EAAE,MAAM,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAAC;IAE/D;;;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.
|
|
3
|
+
"version": "0.1.0-alpha.81",
|
|
4
4
|
"description": "基于 CASL 的前端鉴权 SDK",
|
|
5
5
|
"types": "./lib/index.d.ts",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -15,11 +15,13 @@
|
|
|
15
15
|
"scripts": {
|
|
16
16
|
"build": "rslib build",
|
|
17
17
|
"dev": "rslib build --watch",
|
|
18
|
-
"type-check": "tsc --noEmit"
|
|
18
|
+
"type-check": "tsc --noEmit",
|
|
19
|
+
"prepublishOnly": "npm run build"
|
|
19
20
|
},
|
|
20
21
|
"dependencies": {
|
|
21
|
-
"@casl/ability": "^6.7.
|
|
22
|
-
"@casl/react": "^
|
|
22
|
+
"@casl/ability": "^6.7.5",
|
|
23
|
+
"@casl/react": "^5.0.0",
|
|
24
|
+
"@lark-apaas/internal-slardar": "^0.0.3"
|
|
23
25
|
},
|
|
24
26
|
"devDependencies": {
|
|
25
27
|
"@rsbuild/core": "~1.4.13",
|