member_center/docs/ADMIN_AUTHORIZATION.md
2026-07-03 15:42:49 +09:00

91 lines
3.9 KiB
Markdown

# Admin Authorization
## Purpose
The admin authorization model separates a user's organizational role from the
individual admin capabilities granted to that role. The schema supports multiple
roles even though the initial non-superuser role is only `admin`.
## Core Rules
1. `superuser` is a hard-coded emergency and governance role.
- It does not depend on database permission mappings.
- It bypasses all admin permission checks.
- Creating a replacement superuser or resetting its password remains an
installer responsibility.
- Superuser-only account governance actions continue to require the
`Superuser` authorization policy.
2. Normal admin access uses Role-Based Access Control.
- A user may have one or more Identity roles through `user_roles`.
- A role may have one or more admin permissions through
`admin_role_permissions`.
- A user's effective permissions are the union of permissions assigned to all
of the user's roles.
3. Roles and role-permission mappings are database data.
- Existing ASP.NET Core Identity `roles` and `user_roles` tables remain the
source of role membership.
- `admin_permissions` stores the known permission catalog.
- `admin_role_permissions` maps any Identity role to any admin permission.
- Adding roles such as `support`, `auditor`, or `security_admin` does not
require another schema change.
4. Permission definitions are owned by application code.
- Permission keys are declared in `AdminPermissions`.
- Startup and installer seeding synchronize those known definitions into the
database.
- The database decides which roles receive known permissions; it must not be
used to invent capabilities that have no application implementation.
5. Permissions are action-oriented.
- Controllers require a module permission such as `admin.tenants`.
- Actions also require a capability permission such as
`admin.tenants.create` or `admin.tenants.delete`.
- Operations with materially different authorization boundaries must be
separate actions and separate permission keys.
6. Server-side checks are authoritative.
- Admin controllers retain `[Authorize(Policy = "Admin")]` as the outer admin
boundary.
- Controllers and actions use `AdminPermissionAttribute` for database-backed
permission checks.
- Non-admin access to `/admin/*` continues to return HTTP 404.
- Missing action permissions also return HTTP 404 so inaccessible admin
capabilities are not exposed.
7. Navigation and operation links use the same permission catalog.
- Admin menus reference the same `AdminPermissions` constants used by the
corresponding controller actions.
- Buttons and links are hidden when the current user lacks the target action
permission.
- UI visibility is only a usability measure; direct requests are always
protected by controller/action checks.
## Initial Mapping
The initial `admin` role receives every known permission except permissions
marked as superuser-only. This preserves current behavior while allowing the
mapping to be divided among more roles later.
The initial superuser-only permissions are:
- `admin.accounts.set_admin`
- `admin.accounts.set_disabled`
- `admin.accounts.reset_password`
No role or permission maintenance UI is included yet. Until one is introduced,
the permission catalog is updated in code and role-permission mappings may be
managed through controlled database changes or future installer commands.
## Adding an Admin Capability
1. Add a constant and definition to `AdminPermissions`.
2. Apply the module permission to the controller.
3. Apply the capability permission to every relevant action.
4. Use the same action permission for related menu items, links, and buttons.
5. Add or update role-permission mappings through the approved seed or
administrative workflow.
6. Verify direct access, navigation visibility, `admin`, and `superuser`
behavior.