Summary#
app.Classifications maps each data-sensitivity level to the set of [Role] members permitted to read fields
marked at that level. A level is a DataClass value — PII, Financial, Secret, and so on — and each
Classification pairs one level with a Roles = [ … ] list. A field annotated [Classification(DataClass.PII)] is
then readable only by a principal holding one of the roles listed for PII; to everyone else the field is masked. The
list is declared inside the bare app = new() { … } config object.
enum DataClass { PII, Financial }
app = new() {
Name = "Orders",
Classifications = [
new Classification(DataClass.PII) { Roles = [Role.Staff, Role.Admin] },
new Classification(DataClass.Financial) { Roles = [Role.Admin] },
],
};Signature#
[Role] enum Role { Staff, Admin } // the [Role] enum must be declared
enum DataClass { PII, Financial } // …and the level vocabulary is an enum too
app = new() {
Name = "Orders",
Classifications = [ // one entry per data-sensitivity level
new Classification(DataClass.PII) { // the level this entry governs
Roles = [Role.Staff, Role.Admin], // roles allowed to read fields at this level
},
new Classification(DataClass.Financial) { Roles = [Role.Admin] },
],
};Classifications is a list — an app may map several independent DataClass levels, each to its own set of roles.
Description#
Each Classification has:
DataClass.<Level>— the constructor argument names the sensitivity level this entry governs (PII,Financial,Secret, …). One entry per level. The level vocabulary is an enum the app declares — it need not be calledDataClass, and naming a member no enum declares is a compile error, exactly as it is in the[Classification]attribute.Roles— a list of[Role]enum members. A principal must hold one of these roles to read a field marked at this level. A principal holding none of them sees the field masked.
A field opts into a level with the [Classification] attribute — [Classification(DataClass.<Level>)] on the
member. The classification declared here is what that attribute resolves against: it decides which roles can read the
field. Because Roles references [Role]
members, the [Role] enum must be declared in the app — a role name that doesn't resolve is a compile error that
names the roles you do define.
The whole list lives inside the bare app = new() { Name = "…", Classifications = [ … ] } config object alongside the
app's other configuration.
Examples#
An app that classifies PII fields as readable by staff or admins, and Financial fields as admin-only. The [Role]
enum is declared because Roles references its members:
[Role] enum Role { Staff, Admin }
enum DataClass { PII, Financial }
app = new() {
Name = "Orders",
Classifications = [
new Classification(DataClass.PII) { Roles = [Role.Staff, Role.Admin] },
new Classification(DataClass.Financial) { Roles = [Role.Admin] },
],
};See also#
- role grants (and the first admin) — declaring the
[Role]enum whose members appear inRoles - security { } — entity-level read/write gates that compose with field classifications
- principal predicates (IsAuthenticated / IsAnonymous) and open reads — the principal whose roles are checked against a field's classification