Skip to main content

webiny-admin-permissions

Admin-side permission UI registration and DI-backed permission checking. Use this skill when adding permission controls to the admin UI — schema-based auto-generated forms, injectable permissions via createPermissionsAbstraction/ createPermissionsFeature, typed hooks (createUsePermissions), the HasPermission component (createHasPermission), and the Security.Permissions component props. Covers both simple apps and complex multi-entity permission schemas.

Quellinformationen

Repository
webiny/webiny-js
Letzte Quellaktivität
24. Juli 2026 um 12:20
Erkannte Sprache von SKILL.md
Englisch
Sterne
8.045
Forks
682

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
webiny-admin-permissions
description
Admin-side permission UI registration and DI-backed permission checking. Use this skill when adding permission controls to the admin UI — schema-based auto-generated forms, injectable permissions via createPermissionsAbstraction/ createPermissionsFeature, typed hooks (createUsePermissions), the HasPermission component (createHasPermission), and the Security.Permissions component props. Covers both simple apps and complex multi-entity permission schemas.
# Admin Permissions ## Overview Permissions follow three layers: **domain** (schema), **features** (DI artifacts + registration), and **presentation** (hooks, components, UI config). The framework auto-generates the permission UI from a schema and provides injectable permission checking via the DI container. ## Layer 1: Domain — Permission Schema Define the schema in `src/domain/permissionsSchema.ts`: ```ts import { createPermissionSchema } from "webiny/admin/security"; export const SM_PERMISSIONS_SCHEMA = createPermissionSchema({ prefix: "sm", fullAccess: true, entities: [ { id: "product", title: "Products", permission: "sm.product", scopes: ["full", "own"], actions: [ { name: "rwd" }, { name: "pw" }, { name: "import", label: "Import products" }, { name: "export", label: "Export products" } ] }, { id: "category", title: "Categories", permission: "sm.category", scopes: ["full"], actions: [{ name: "rwd" }] }, { id: "settings", title: "Settings", permission: "sm.settings", scopes: ["full"] } ] }); ``` ### Schema Reference | Field | Type | Required | Description | | ---------------- | -------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------ | | `prefix` | `string` | Yes | Permission prefix (e.g., `"sm"`) | | `fullAccess` | `true \| object` | Yes | `true` for standard full access. Pass an object with custom boolean flags for full-access extras (e.g., `{ canForceUnlock: true }`). | | `readOnlyAccess` | `boolean` | No | Whether to show a "Read-only access" option | | `entities` | `EntityDefinition[]` | No | Entity definitions. Omit for binary full/no access. | ### Entity Definition | Field | Type | Required | Description | | ------------ | -------------------------------------- | -------- | ---------------------------------------------- | | `id` | `string` | Yes | Unique identifier for form field naming | | `title` | `string` | No | Display title. Falls back to `id`. | | `permission` | `string` | Yes | Permission name emitted (e.g., `"sm.product"`) | | `scopes` | `("full" \| "own")[]` | Yes | Available access scopes | | `actions` | `ActionDefinition[]` | No | Actions on this entity | | `dependsOn` | `{ entity: string; requires: string }` | No | Dependency on another entity | ### Actions - `{ name: "rwd" }` — Read/Write/Delete select dropdown. Auto-set to `"rwd"` when scope is `"own"`. - `{ name: "pw" }` — Publish/Unpublish checkbox group. - `{ name: "custom", label: "Label" }` — Custom boolean flag. ### Entity Dependencies Child entities can depend on a parent. If the parent lacks the required action, the child is pruned from output. `"own"` scope cascades to dependents. ```ts { id: "review", permission: "sm.review", scopes: ["full", "own"], actions: [{ name: "rwd" }], dependsOn: { entity: "product", requires: "r" } } ``` ### Simple Apps (No Entities) Omit `entities` for binary full/no access: ```ts export const MA_PERMISSIONS_SCHEMA = createPermissionSchema({ prefix: "ma", fullAccess: true }); ``` --- ## Layer 2: Features — DI Artifacts + Registration ### Abstraction (`src/features/permissions/abstractions.ts`) ```ts import { createPermissionsAbstraction } from "webiny/admin/security"; import type { Permissions } from "webiny/admin/security"; import { SM_PERMISSIONS_SCHEMA } from "~/domain/permissionsSchema.js"; export const SmPermissions = createPermissionsAbstraction(SM_PERMISSIONS_SCHEMA); export namespace SmPermissions { export type Interface = Permissions<typeof SM_PERMISSIONS_SCHEMA>; } ``` ### Feature (`src/features/permissions/feature.ts`) ```ts import { createPermissionsFeature } from "webiny/admin/security"; import { SM_PERMISSIONS_SCHEMA } from "~/domain/permissionsSchema.js"; import { SmPermissions } from "./abstractions.js"; export const SmPermissionsFeature = createPermissionsFeature(SM_PERMISSIONS_SCHEMA, SmPermissions); ``` ### Extension Registration Register the feature and the permission UI in your extension component: ```tsx import { AdminConfig, RegisterFeature } from "webiny/admin/security"; import { ReactComponent as Icon } from "@webiny/icons/shield.svg"; import { SM_PERMISSIONS_SCHEMA } from "~/domain/permissionsSchema.js"; import { SmPermissionsFeature } from "~/features/permissions/feature.js"; const { Security } = AdminConfig; export const Extension = () => { return ( <> <RegisterFeature feature={SmPermissionsFeature} /> <AdminConfig> <Security.Permissions name="store-manager" title="Store Manager" description="Manage Store Manager permissions." icon={<Icon />} schema={SM_PERMISSIONS_SCHEMA} /> {/* Routes, menus, etc. */} </AdminConfig> </> ); }; ``` --- ## Layer 3: Presentation — Hooks & Components ### `usePermissions` Hook ```ts // src/presentation/security/usePermissions.ts import { createUsePermissions } from "webiny/admin/security"; import { SmPermissions } from "~/features/permissions/abstractions.js"; export const usePermissions = createUsePermissions(SmPermissions); ``` Usage: ```ts const permissions = usePermissions(); permissions.canAccess("product"); // has any access permissions.canRead("product"); // rwd includes "r" permissions.canCreate("product"); // rwd includes "w" permissions.canEdit("product", item); // rwd includes "w", respects own scope permissions.canDelete("product"); // rwd includes "d" permissions.canPublish("product"); // pw includes "p" permissions.canUnpublish("product"); // pw includes "u" permissions.canAction("import", "product"); // custom boolean flag ``` Entity IDs are fully typed — `canRead("bogus")` produces a type error. ### `HasPermission` Component ```tsx // src/presentation/security/HasPermission.tsx import { createHasPermission } from "webiny/admin/security"; import { SmPermissions } from "~/features/permissions/abstractions.js"; import { SM_PERMISSIONS_SCHEMA } from "~/domain/permissionsSchema.js"; export const HasPermission = createHasPermission(SmPermissions, SM_PERMISSIONS_SCHEMA); ``` Usage in JSX: ```tsx <HasPermission entity="product"> {/* Rendered if user can access "product" */} </HasPermission> <HasPermission any={["product", "category"]}> {/* Rendered if user can access ANY of these entities */} </HasPermission> <HasPermission all={["product", "category"]}> {/* Rendered if user can access ALL of these entities */} </HasPermission> <HasPermission entity="product" action="read"> {/* Rendered if user canRead("product") */} </HasPermission> <HasPermission entity="product" allActions={["read", "publish"]}> {/* Rendered if user canRead AND canPublish "product" */} </HasPermission> <HasPermission entity="product" someActions={["import", "export"]}> {/* Rendered if user can do ANY of these custom actions */} </HasPermission> ``` --- ## DI Injection in Features Inject permissions into feature implementations: ```ts import type { SmPermissions } from "~/features/permissions/abstractions.js"; import { SmPermissions as SmPermissionsAbstraction } from "~/features/permissions/abstractions.js"; class SomeFeatureImpl { constructor(private permissions: SmPermissions.Interface) {} doSomething() { if (this.permissions.canEdit("product")) { // ... } } } const SomeFeature = SomeAbstraction.createImplementation({ implementation: SomeFeatureImpl, dependencies: [SmPermissionsAbstraction] }); ``` --- ## `Security.Permissions` Props | Prop | Type | Required | Description | | ------------- | ------------------ | ------------------------- | ----------------------------------------------- | | `name` | `string` | Yes | Unique identifier for this permission renderer | | `title` | `string` | Yes | Display title in the accordion header | | `description` | `string` | No | Description shown below the title | | `icon` | `ReactElement` | No | Icon in the accordion header | | `schema` | `PermissionSchema` | One of `schema`/`element` | Auto-generate UI from schema | | `element` | `ReactElement` | One of `schema`/`element` | Fully custom permission UI | | `system` | `boolean` | No | If `true`, renders before app-level permissions | --- ## File Structure ``` src/ ├── domain/ │ └── permissionsSchema.ts # createPermissionSchema() ├── features/ │ └── permissions/ │ ├── abstractions.ts # createPermissionsAbstraction() + namespace type │ └── feature.ts # createPermissionsFeature() ├── presentation/ │ └── security/ │ ├── usePermissions.ts # createUsePermissions() │ └── HasPermission.tsx # createHasPermission() └── Extension.tsx # RegisterFeature + Security.Permissions ``` ## Matching API-Side Permissions The admin schema and the API-side `createPermissions` schema should use the **same prefix, entity IDs, and action names**. This ensures the permissions emitted by the admin UI are correctly evaluated by the API. ``` Admin: createPermissionSchema({ prefix: "sm", entities: [{ id: "product", permission: "sm.product", ... }] })
Auf GitHub ansehen
Diese SKILL.md ist sehr gross, daher zeigt SkillsMP hier nur den ersten Abschnitt. Auf GitHub ansehen