bf1a19426a
* fix: form * refactor: schema-initializer * fix: bug * refactor: schema initializer * refactor: rename * fix: delete SchemaInitializerProvider * refactor: props `insert` to hooks `useSchemaInitializerV2` * fix: bug * refactor: delete `SchemaInitializer.Button` * refactor: delete old SchemaInitializer * fix: bug * fix: workflow * fix: docs * fix: bug * fix: bug * feat: style * fix: remove v2 * fix: visible * fix: bug * fix: item hook * feat: item hook * fix: add search DataBlockInitializer * fix: build bug * fix: style bug * fix: style bug * fix: test bug * fix: test bug * fix: rerender bug * fix: remove menu select * fix: bug * chore: add aria-label for SchemaInitializerButton * refactor: rename name to camel case * fix: menu height bug * fix: build errors * fix: build errors * fix: bug * fix: bug * fix: performance * test: add test for header * fix: sidebar is not refresh (T-2422) * feat(e2e): support to add group page and link page * chore: make sure the page is configurable when using page.goto * test: add tests for menu initializer * fix: imporve code * chore: fix build error * chore: optimize locator of menu item * refactor: rename testid for select * test: make tests passing * fix: make tests passing * chore: upgrade vitest to v0.34.6 * chore: increase timeout of e2e * feat: core * fix: revert schema initializer demos * test: menu, page tabs, page grid, table column * fix: schema button interface * feat: refactor: page tab settings * feat: page settings * fix: dumirc * fix: export CSSVariableProvider * feat: lazy render * fix: form-item * fix: general schema desinger * feat: filter form item settings * refactor: form-v2 schema settings * refactor: form-v1 schema settings * refactor: action schema settings * fix: action bug * fix: form-item bug * fix: types error * docs: schema settings doc * docs: schema settings * feat: schema setting item add name * fix: visible lazy render bug * fix: revert form item filter * fix: test bug * fix: test JSON.parse bug * fix: test bug * fix: improve styling * fix: styling * fix: cleanup * fix: token.borderRadiusSM * fix: bug * test: add tests * fix: style bug * fix: add chart performance * feat: add SchemaDesignerContext * fix: bug * fix: test bug * style: create record action style improve * fix: make test passing * chore: mack tests passing * chore: make tests passing * test: fix tests * style: style revert * fix: bug * fix: data selector * fix: fix tests * fix: fix tests * fix: delete PluginManagerContext * refactor: improve router and add SchemaComponentProvider & CSSVariableProvider to MainComponent * fix: add dn and field builtin to SchemaSettingWrapper * feat: update docs * refactor: application providers * fix: test bug * fix: fix tests * chore: make test passing * feat: update docs * chore: rename collection name * feat: update docs * chore: skip weird test * fix: blockInitializers media to otherBlocks * fix: cancel to skip test * fix: bug * test: add test * refactor: migrate to small files * test: add tests for form block settings * chore: format * fix: add chart scroll bug * refactor: action designer improve * refactor: formitem designer schemaSetting * feat: schemaSettingsManager and schemaInitializerManager addItem and removeItem * test: add tests for color field in creating block * test: add tests for email field in creating block * test: make tests passing * perf: reduce fields number * fix: sub menu bug * test: add tests basic in editing form * test: add tests basic in details form * fix: improve code * test: make tests passing * test(plugin-mock-collections): add color for enum options * refactor: improve code * fix: bug * fix: bug * refactor: convert parameters to destructured object * test: add tests choices * test: add tests media * test: add tests for datetime in creating form * feat(plugin-mock-collection): generate faker time * test: add tests for datetime in editing form * test: add tests for datetime in details form * fix: bug * feat: improve code * test: add tests for relation fields * fix: rename SchemaSettings * fix: type bug * refactor: useDesinger() * fix: bug * fix: bug * fix: build tip * fix: designableState * fix: bug * fix: designable * fix: designable * test: add tests for relation fields * test: add tests for relation fields * test: add tests for relation fields * feat: client api doc * test: add tests for relation fields * test: avoid errors * test: make tests passing * fix: bug * test: make tests passing * test: add tests for advanced fields * test: increase e2e timeout-minutes to 60 * fix: bug * fix: improve code * feat: add schema initailizer component demos * test: make tests passing * fix: schema settings demos * feat: shallowMerge & deepMerge * test: reduce number of tests * test: make tests passing * feat: updates * fix: add Initializer Internal * demos: useSchemaSettingsRender * test: make tests passing * test: make tests passing * fix: improve docs * fix: bug * chore: upgrade dumi theme * test: make tests passing * test: add tests for linkage rules * test: add test for form data templates * test: add tests for default value * test: reduce number of tests * fix: dn.deepMerge * fix: bug * fix: bug * fix: toolbar * fix: docs ssr * test: add tests for system fields * test: add tests for actions * fix: bug * test: add tests for lazy loading of variables * test: make testing more stable * fix: update docs * fix: bug --------- Co-authored-by: Rain <958414905@qq.com> Co-authored-by: chenos <chenlinxh@gmail.com> Co-authored-by: katherinehhh <katherine_15995@163.com>
260 lines
6.3 KiB
Markdown
260 lines
6.3 KiB
Markdown
# ACL
|
||
|
||
## Overview
|
||
|
||
ACL is the permission control module in NocoBase. After registering roles and resources in ACL and configuring corresponding permissions, you can authenticate permissions for roles.
|
||
|
||
### Basic Usage
|
||
|
||
```javascript
|
||
const { ACL } = require('@nocobase/acl');
|
||
|
||
const acl = new ACL();
|
||
|
||
// Define a role named member
|
||
const memberRole = acl.define({
|
||
role: 'member',
|
||
});
|
||
|
||
// Grant the role of member list permission of the posts resource
|
||
memberRole.grantAction('posts:list');
|
||
|
||
acl.can('member', 'posts:list'); // true
|
||
acl.can('member', 'posts:edit'); // null
|
||
```
|
||
|
||
### Concepts
|
||
|
||
* Role (`ACLRole`): Object that needs permission authentication.
|
||
* Resource (`ACLResource`):In NocoBase ACL, a resource usually corresponds to a database table; it is conceptually analogous to the Resource in Restful API.
|
||
* Action: Actions to be taken on resources, such as `create`, `read`, `update`, `delete`, etc.
|
||
* Strategy (`ACLAvailableStrategy`): Normally each role has its own permission strategy, which defines the default permissions of the role.
|
||
* Grant Action: Call the `grantAction` function in `ACLRole` instance to grant access to `Action` for the role.
|
||
* Authentication: Call the `can` function in `ACL` instance, and return the authentication result of the user.
|
||
|
||
## Class Methods
|
||
|
||
### `constructor()`
|
||
|
||
To create a `ACL` instance.
|
||
|
||
```typescript
|
||
import { ACL } from '@nocobase/database';
|
||
|
||
const acl = new ACL();
|
||
```
|
||
|
||
### `define()`
|
||
|
||
Define a ACL role.
|
||
|
||
**Signature**
|
||
|
||
* `define(options: DefineOptions): ACLRole`
|
||
|
||
**Type**
|
||
|
||
```typescript
|
||
interface DefineOptions {
|
||
role: string;
|
||
allowConfigure?: boolean;
|
||
strategy?: string | AvailableStrategyOptions;
|
||
actions?: ResourceActionsOptions;
|
||
routes?: any;
|
||
}
|
||
```
|
||
|
||
**Detailed Information**
|
||
|
||
* `role` - Name of the role
|
||
|
||
```typescript
|
||
// Define a role named admin
|
||
acl.define({
|
||
role: 'admin',
|
||
});
|
||
```
|
||
|
||
* `allowConfigure` - Whether to allow permission configuration
|
||
* `strategy` - Permission strategy of the role
|
||
* It can be a name of strategy in `string`, means to use a strategy that is already defined.
|
||
* Or `AvailableStrategyOptions` means to define a new strategy for this role, refer to [`setAvailableActions()`](#setavailableactions).
|
||
* `actions` - Pass in the `actions` objects accessible to the role when defining the role, then call `aclRole.grantAction` in turn to grant resource permissions. Refer to [`aclRole.grantAction`](./acl-role.md#grantaction) for details
|
||
|
||
```typescript
|
||
acl.define({
|
||
role: 'admin',
|
||
actions: {
|
||
'posts:edit': {}
|
||
},
|
||
});
|
||
// Equivalent to
|
||
const role = acl.define({
|
||
role: 'admin',
|
||
});
|
||
|
||
role.grantAction('posts:edit', {});
|
||
```
|
||
|
||
### `getRole()`
|
||
|
||
Get registered role objects by role name.
|
||
|
||
**Signature**
|
||
|
||
* `getRole(name: string): ACLRole`
|
||
|
||
### `removeRole()`
|
||
|
||
Remove role by role name.
|
||
|
||
**Signature**
|
||
|
||
* `removeRole(name: string)`
|
||
|
||
### `can()`
|
||
|
||
Authentication function.
|
||
|
||
**Signature**
|
||
|
||
* `can(options: CanArgs): CanResult | null`
|
||
|
||
**Type**
|
||
|
||
```typescript
|
||
interface CanArgs {
|
||
role: string; // Name of the role
|
||
resource: string; // Name of the resource
|
||
action: string; // Name of the action
|
||
}
|
||
|
||
interface CanResult {
|
||
role: string; // Name of the role
|
||
resource: string; // Name of the resource
|
||
action: string; // Name of the action
|
||
params?: any; // Parameters passed in when registering the permission
|
||
}
|
||
|
||
```
|
||
|
||
**Detailed Information**
|
||
|
||
The `can` method first checks if the role has the corresponding `Action` permission registered; if not, it checks if the `strategy` and the role matches. It means that the role has no permissions if it returns `null`; else it returns the `CanResult` object, which means that the role has permissions.
|
||
|
||
**Example**
|
||
|
||
```typescript
|
||
// Define role and register permissions
|
||
acl.define({
|
||
role: 'admin',
|
||
actions: {
|
||
'posts:edit': {
|
||
fields: ['title', 'content'],
|
||
},
|
||
},
|
||
});
|
||
|
||
const canResult = acl.can({
|
||
role: 'admin',
|
||
resource: 'posts',
|
||
action: 'edit',
|
||
});
|
||
/**
|
||
* canResult = {
|
||
* role: 'admin',
|
||
* resource: 'posts',
|
||
* action: 'edit',
|
||
* params: {
|
||
* fields: ['title', 'content'],
|
||
* }
|
||
* }
|
||
*/
|
||
|
||
acl.can({
|
||
role: 'admin',
|
||
resource: 'posts',
|
||
action: 'destroy',
|
||
}); // null
|
||
```
|
||
|
||
### `use()`
|
||
|
||
**Signature**
|
||
|
||
* `use(fn: any)`
|
||
Add middleware function into middlewares.
|
||
|
||
### `middleware()`
|
||
|
||
Return a middleware function to be used in `@nocobase/server`. After using this `middleware`, `@nocobase/server` will perform permission authentication before each request is processed.
|
||
|
||
### `allow()`
|
||
|
||
Set the resource as publicly accessible.
|
||
|
||
**Signature**
|
||
|
||
* `allow(resourceName: string, actionNames: string[] | string, condition?: string | ConditionFunc)`
|
||
|
||
**Type**
|
||
|
||
```typescript
|
||
type ConditionFunc = (ctx: any) => Promise<boolean> | boolean;
|
||
```
|
||
|
||
**Detailed Information**
|
||
|
||
* resourceName - Name of the resource
|
||
* actionNames - Name of the resource action
|
||
* condition? - Configuration of the validity condition
|
||
* Pass in a `string` to use a condition that is already defined; Use the `acl.allowManager.registerCondition` method to register a condition.
|
||
```typescript
|
||
acl.allowManager.registerAllowCondition('superUser', async () => {
|
||
return ctx.state.user?.id === 1;
|
||
});
|
||
|
||
// Open permissions of the users:list with validity condition superUser
|
||
acl.allow('users', 'list', 'superUser');
|
||
```
|
||
* Pass in ConditionFunc, which can take the `ctx` parameter; return `boolean` that indicate whether it is in effect.
|
||
```typescript
|
||
// user:list accessible to user with ID of 1
|
||
acl.allow('users', 'list', (ctx) => {
|
||
return ctx.state.user?.id === 1;
|
||
});
|
||
```
|
||
|
||
**Example**
|
||
|
||
```typescript
|
||
// Register users:login to be publicly accssible
|
||
acl.allow('users', 'login');
|
||
```
|
||
|
||
### `setAvailableActions()`
|
||
|
||
**Signature**
|
||
|
||
* `setAvailableStrategy(name: string, options: AvailableStrategyOptions)`
|
||
|
||
Register an available permission strategy.
|
||
|
||
**Type**
|
||
|
||
```typescript
|
||
interface AvailableStrategyOptions {
|
||
displayName?: string;
|
||
actions?: false | string | string[];
|
||
allowConfigure?: boolean;
|
||
resource?: '*';
|
||
}
|
||
```
|
||
|
||
**Detailed Information**
|
||
|
||
* displayName - Name of the strategy
|
||
* allowConfigure - Whether this strategy has permission of **resource configuration**; if set to `true`, the permission that requests to register as `configResources` resource in `ACL` will return pass
|
||
* actions - List of actions in the strategy, wildcard `*` is supported
|
||
* resource - Definition of resource in the strategy, wildcard `*` is supported
|