refactor(auth): domain-specific role names (consistent convention)
User feedback: универсальный 'ordinis:approver' отступал от convention
'ordinis:<domain>:<action>'. Меняю на domain-specific:
WorkflowRoles constants:
- APPROVER → SCHEMA_REVIEWER ('ordinis:schema:reviewer')
- PUBLISHER → SCHEMA_PUBLISHER ('ordinis:schema:publisher')
- Новая RECORD_REVIEWER ('ordinis:record:reviewer')
Applied:
- SchemaDraftService.decide() → require SCHEMA_REVIEWER
- SchemaDraftService.publish() → require SCHEMA_PUBLISHER
- DraftService.approve() / .reject() → require RECORD_REVIEWER
Frontend usePermissions.ts:
- ROLE_APPROVER + ROLE_PUBLISHER → ROLE_SCHEMA_REVIEWER +
ROLE_SCHEMA_PUBLISHER + ROLE_RECORD_REVIEWER
- Новый hook useCanReviewRecord() для record draft actions
Keycloak setup (updated):
- ordinis:schema:reviewer
- ordinis:schema:publisher
- ordinis:record:reviewer
(Composite role 'ordinis:admin' = all три + scope roles — для удобства.)
This commit is contained in:
@@ -4,10 +4,9 @@ import { useAuth } from 'react-oidc-context'
|
||||
* Permission helpers для schema + record workflow. Phase 1d — **ACTIVE**:
|
||||
* читает {@code realm_access.roles} из JWT и гейтит actions.
|
||||
*
|
||||
* <p>Naming convention: colon-separated namespace
|
||||
* {@code ordinis:<domain>:<action>} consistent с scope ACL ролями
|
||||
* ({@code ordinis:client:public}). Backend parser в
|
||||
* {@code ScopeContext.java} / {@code WorkflowRoles.java}.
|
||||
* <p>Naming convention: colon-separated {@code ordinis:<domain>:<action>}
|
||||
* pattern (consistent с scope ACL {@code ordinis:client:public}). Backend
|
||||
* parser в {@code WorkflowRoles.java}.
|
||||
*
|
||||
* <p>Backend enforcement (см. {@code WorkflowRoles}):
|
||||
* <ul>
|
||||
@@ -21,13 +20,19 @@ import { useAuth } from 'react-oidc-context'
|
||||
* backend всё равно 403'нет на прямой API call.
|
||||
*
|
||||
* <p><b>Migration note (Phase 1d enforcement):</b> Keycloak realm `nstart`
|
||||
* должен иметь созданные роли {@code ordinis:approver} и
|
||||
* {@code ordinis:publisher}, и actual reviewer-users должны их получить.
|
||||
* До этого все decide / publish операции вернут {@code 403 forbidden_role}.
|
||||
* должен иметь созданные роли:
|
||||
* <ul>
|
||||
* <li>{@code ordinis:schema:reviewer} — schema decide</li>
|
||||
* <li>{@code ordinis:schema:publisher} — schema publish</li>
|
||||
* <li>{@code ordinis:record:reviewer} — record approve/reject</li>
|
||||
* </ul>
|
||||
* и actual reviewer-users должны их получить. До этого все decide /
|
||||
* publish операции вернут {@code 403 forbidden_role}.
|
||||
*/
|
||||
|
||||
export const ROLE_APPROVER = 'ordinis:approver'
|
||||
export const ROLE_PUBLISHER = 'ordinis:publisher'
|
||||
export const ROLE_SCHEMA_REVIEWER = 'ordinis:schema:reviewer'
|
||||
export const ROLE_SCHEMA_PUBLISHER = 'ordinis:schema:publisher'
|
||||
export const ROLE_RECORD_REVIEWER = 'ordinis:record:reviewer'
|
||||
|
||||
/** Достаёт realm roles из JWT (Keycloak claim path: realm_access.roles). */
|
||||
function realmRoles(profile: unknown): string[] {
|
||||
@@ -43,19 +48,22 @@ function hasRole(profile: unknown, role: string): boolean {
|
||||
return realmRoles(profile).includes(role)
|
||||
}
|
||||
|
||||
/** Может ли актор approve / request_changes / reject schema OR record draft. */
|
||||
/** Может ли актор approve / request_changes / reject schema draft. */
|
||||
export function useCanReviewSchema(): boolean {
|
||||
const auth = useAuth()
|
||||
return auth.isAuthenticated && hasRole(auth.user?.profile, ROLE_APPROVER)
|
||||
return auth.isAuthenticated && hasRole(auth.user?.profile, ROLE_SCHEMA_REVIEWER)
|
||||
}
|
||||
|
||||
/** Universal alias — то же что {@link useCanReviewSchema}. */
|
||||
export const useCanReviewDraft = useCanReviewSchema
|
||||
/** Может ли актор approve / reject record draft. */
|
||||
export function useCanReviewRecord(): boolean {
|
||||
const auth = useAuth()
|
||||
return auth.isAuthenticated && hasRole(auth.user?.profile, ROLE_RECORD_REVIEWER)
|
||||
}
|
||||
|
||||
/** Может ли актор publish approved schema draft (bump live version). */
|
||||
export function useCanPublishSchema(): boolean {
|
||||
const auth = useAuth()
|
||||
return auth.isAuthenticated && hasRole(auth.user?.profile, ROLE_PUBLISHER)
|
||||
return auth.isAuthenticated && hasRole(auth.user?.profile, ROLE_SCHEMA_PUBLISHER)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user