- Halo Plugin 后端(Java/Gradle),含 DarkModePlugin 主类和测试 - Vue 3 + TypeScript 前端 UI,包含主题切换组件和设置页面 - 暗色模式 CSS 变量和覆盖样式(布局/编辑器/表单/滚动条等) - 设计文档和调查文档 - Halo 插件/主题开发 Agent Skills Co-Authored-By: Claude <noreply@anthropic.com>
6.3 KiB
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 File
Place YAML files in src/main/resources/extensions/.
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/<group>/<version>/<resource>[/<name>/<subresource>]:
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):
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:
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.
@Component
public class MyFilter implements AdditionalWebFilter {
@Override
public int getOrder() { return Ordered.LOWEST_PRECEDENCE; }
@Override
public Mono<Void> 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:
ReactiveSecurityContextHolder.getContext()
.map(SecurityContext::getAuthentication)
.map(Authentication::getName)
.defaultIfEmpty(AnonymousUserConst.PRINCIPAL);
UI Permissions
Used in frontend route guards:
meta: {
permissions: ["plugin:my-plugin:person:view"];
}
Check at runtime:
import { utils } from "@halo-dev/ui-shared";
utils.permission.has(["plugin:my-plugin:person:view"]); // true/false