Skip to main content
Version: 2.x

Keeping the Policies DRY

ZenStack's access policies provide you with a powerful tool to model authorization in a intuitive and declarative way. However, as your application grows, you may find yourself repeating the same access policy patterns across multiple models. In this section, we'll review a typical type of duplication and show you how to avoid it by delegating to related models.

Parent-Child Duplication

If your application has a hierarchy of models, you'll quite often notice that the child models repeat the access policies of their parent. This can be found in our Todo schema, where List and Todo models have a parent-child relationship:

model List {
...

// require login
@@deny('all', auth() == null)

// can be read by space members if not private
@@allow('read', owner == auth() || (space.members?[user == auth()] && !private))

// when create, owner must be set to current user, and user must be in the space
@@allow('create,update', owner == auth() && space.members?[user == auth()])

...
}

model Todo {
...

// require login
@@deny('all', auth() == null)

// owner has full access
@@allow('all', list.owner == auth())

// space members have full access if the parent List is not private
@@allow('all', list.space.members?[user == auth()] && !list.private)
}

Although not a 100% match, the rules of Todo closely resemble those of List. How can we avoid such duplication and stay DRY?

Delegating Access Control to a Relation

If we carefully inspect the policies, we'll find the rules of Todo can summarized into a single statement:

One has full access to a Todo entity if he can read its parent List entity.

ZenStack provides a check() attribute function for you to delegate access control of the current model to a relation. Let's refactor the Todo model to use this feature 🛠️:

model Todo {
...

// full access if the parent list is readable
@@allow('all', check(list, 'read'))
}

When authorizing an operation on a Todo (e.g., "update"), ZenStack will make the decision based on if the related List entity is readable. If you adjust the rules on List in the future, the Todo model automatically follows without needing any changes.

The check() API can be used in both model-level and field-level policies. See the API Reference for more details.

Comments
Feel free to ask questions, give feedback, or report issues.

Don't Spam


You can edit/delete your comments by going directly to the discussion, clicking on the 'comments' link below