Skip to content

Field & column security

RBAC gates a whole resource; field & column security narrows access within a record. It is authored in the view XML and enforced on the server — the UI rules are mirrored, never trusted.

A <Column> can carry RolesAllowed to restrict who sees it, and StyleClassesExpression for conditional styling. When a user lacks the roles for a column, the server omits it from both the metadata and the row data (via ColumnVisibilityHelper) — the column isn’t merely hidden in CSS, its values never leave the server. See Column & field expressions.

An <EditorField> supports smart attributes that combine a state with an optional condition:

  • Required, Disabled, Hidden — each may be a literal (true) or an expression over other fields (e.g. @Status == 'Approved').
  • Allow / Deny — role lists or expressions that grant or refuse access to the field.

These are resolved into a concrete per-request state by FieldStateResolver, and — crucially — re-enforced on submit by FieldAccessEnforcer. Genie ships a C# port of the UI’s eval-free expression interpreter so the same rule that hid or disabled a field in the browser is evaluated again on the server before a write is accepted.

Which state an edit is judged against. On an update, access locks (Disabled, Allow, Deny) are evaluated against the stored row — so a caller can’t flip a field that drives a lock (e.g. Deny="@Status == 'Locked'") to dodge it in the same request. Visibility (Hidden) and Required are evaluated against the submitted values — so a field the user legitimately reveals by changing its driver in the same submit (the classic pair Hidden="@Status != 'Discontinued'" + Required="@Status == 'Discontinued'") is accepted and its value saved, rather than being discarded as “hidden per the old state” and then reported as required.

Row actions are gated too: RowActionAccess checks the user’s verbs (and any action-level rules) before an execute-row-action call runs the action’s SQL. A DisplayExpression can hide an action in the UI, but the server still re-checks access on execution. See Actions & row actions.

Concern Authored on Enforced by
Column visibility <Column RolesAllowed> ColumnVisibilityHelper
Field state (required/disabled/hidden) <EditorField Required/Disabled/Hidden> FieldStateResolver + FieldAccessEnforcer
Field access (allow/deny) <EditorField Allow/Deny> FieldAccessEnforcer
Field values (required/regex/bounds/rules) <EditorField RegexValidation> + <Validations> FieldValidationEvaluator (+ FieldSqlValidationRunner for Type="Sql")
Row-action access <Action> RowActionAccess

Value validation deliberately skips a field that is hidden, disabled or Allow/Deny-locked for this caller: the value has already been replaced with the stored/default one, so validating it would punish the user for data they can’t reach. See Validation.