# RBAC & Role Templates > ⚠️ **Not all plugins need to create RoleTemplate resources.** All plugin APIs are restricted to super-admin by default. If your plugin is intended for super-admin use only, there is no need to create or configure RoleTemplates at all. > > Only create RoleTemplates in the following scenarios: > > - When certain APIs need to be accessible to other roles (e.g., editor, contributor) > - When certain APIs need to be publicly accessible to unauthenticated users (anonymous) > - When the plugin UI requires role-based permission controls All plugin APIs (auto-generated CRUD + custom) are restricted to super-admin by default. To allow other users access, define **role templates**. > Source references (Halo main branch): > > - [Role template anonymous](https://github.com/halo-dev/halo/blob/main/application/src/main/resources/extensions/role-template-anonymous.yaml) > - [Role template authenticated](https://github.com/halo-dev/halo/blob/main/application/src/main/resources/extensions/role-template-authenticated.yaml) > - [Plugin photos role templates (production example)](https://github.com/halo-sigs/plugin-photos/blob/main/src/main/resources/extensions/roleTemplate.yaml) ## Role Template File Place YAML files in `src/main/resources/extensions/`. ```yaml apiVersion: v1alpha1 kind: Role metadata: name: my-plugin-role-view-persons labels: halo.run/role-template: "true" annotations: rbac.authorization.halo.run/module: "Persons Management" rbac.authorization.halo.run/display-name: "View Persons" rbac.authorization.halo.run/ui-permissions: | ["plugin:my-plugin:person:view"] rules: - apiGroups: ["my-plugin.halo.run"] resources: ["my-plugin/persons"] verbs: ["get", "list"] --- apiVersion: v1alpha1 kind: Role metadata: name: my-plugin-role-manage-persons labels: halo.run/role-template: "true" annotations: rbac.authorization.halo.run/dependencies: | ["my-plugin-role-view-persons"] rbac.authorization.halo.run/module: "Persons Management" rbac.authorization.halo.run/display-name: "Manage Persons" rbac.authorization.halo.run/ui-permissions: | ["plugin:my-plugin:person:manage"] rules: - apiGroups: ["my-plugin.halo.run"] resources: ["my-plugin/persons"] verbs: ["*"] ``` ## Key Rules | Element | Description | | -------------------------------------------------------- | -------------------------------------------------- | | `metadata.name` | Must use plugin name as prefix to avoid collisions | | `labels.halo.run/role-template: "true"` | Required to mark as template | | `annotations.rbac.authorization.halo.run/dependencies` | Other roles this role requires | | `annotations.rbac.authorization.halo.run/module` | UI grouping name | | `annotations.rbac.authorization.halo.run/display-name` | Human-readable name | | `annotations.rbac.authorization.halo.run/ui-permissions` | Frontend permission strings | ## Resource Rules For APIs matching `/apis///[//]`: ```yaml rules: - apiGroups: ["my-plugin.halo.run"] resources: ["my-plugin/persons"] resourceNames: ["zhangsan"] # optional, for single resource verbs: ["get", "list"] ``` ## Non-Resource Rules For APIs not matching resource patterns (e.g., `/healthz`): ```yaml rules: - nonResourceURLs: ["/healthz", "/healthz/*"] verbs: ["get"] ``` ## Verbs | Verb | HTTP Method | Description | | ------------------ | --------------- | --------------------------------------- | | `create` | POST | Create new resource | | `get` | GET | Get single resource (with name in path) | | `list` | GET | List resources (without name in path) | | `watch` | GET (WebSocket) | Watch resource changes | | `update` | PUT | Full update | | `patch` | PATCH | Partial update | | `delete` | DELETE | Delete single resource | | `deletecollection` | DELETE | Delete collection | ## Aggregation Merge plugin permissions into existing Halo roles: ```yaml metadata: labels: halo.run/role-template: "true" halo.run/hidden: "true" # hide from UI rbac.authorization.halo.run/aggregate-to-anonymous: "true" rules: - apiGroups: ["api.my-plugin.halo.run"] resources: ["public-data"] verbs: ["get", "list"] ``` Available aggregation targets: `anonymous`, `authenticated`, `editor`, etc. ## Special Roles | Role | Description | | --------------- | -------------------------------------------------------- | | `anonymous` | Unauthenticated visitors | | `authenticated` | All logged-in users (minimum permissions) | | `super-role` | Full system access | | `guest` | No explicit permissions (only anonymous + authenticated) | ## Web Filters Add custom WebFlux filters for request interception. ```java @Component public class MyFilter implements AdditionalWebFilter { @Override public int getOrder() { return Ordered.LOWEST_PRECEDENCE; } @Override public Mono filter(ServerWebExchange exchange, WebFilterChain chain) { // Runs before security chain return chain.filter(exchange); } } ``` `AfterSecurityWebFilter` runs after the security chain (for caching, analytics, etc.). ## ReactiveSecurityContextHolder Access the current authentication in reactive code: ```java ReactiveSecurityContextHolder.getContext() .map(SecurityContext::getAuthentication) .map(Authentication::getName) .defaultIfEmpty(AnonymousUserConst.PRINCIPAL); ``` ## UI Permissions Used in frontend route guards: ```ts meta: { permissions: ["plugin:my-plugin:person:view"]; } ``` Check at runtime: ```ts import { utils } from "@halo-dev/ui-shared"; utils.permission.has(["plugin:my-plugin:person:view"]); // true/false ```