216 lines
7.8 KiB
Markdown
216 lines
7.8 KiB
Markdown
|
||
# Permissions: Groups, Scopes, Authorization Rules
|
||
|
||
In Unify, the **permissions system** is designed to give you full control over who can **read**, **write**, or **delete** data, while allowing you to enforce security at various levels of the application.
|
||
|
||
Unify offers a **flexible**, **declarative** approach to managing permissions across different objects, allowing you to define **authorization rules** based on:
|
||
|
||
* **User Groups** (e.g., admin, guest, member)
|
||
* **Scopes** (e.g., a column, a table, or an entire resource)
|
||
* **Actions** (e.g., READ, WRITE, DELETE)
|
||
|
||
## 1. Groups: Defining User Roles
|
||
|
||
In Unify, **Groups** represent user roles, and each group has certain **permissions** associated with it. These groups can be used to control access at various levels, such as:
|
||
|
||
* Viewing data
|
||
* Editing data
|
||
* Deleting data
|
||
|
||
### Example: Defining Groups
|
||
|
||
```js
|
||
import groups from '/user/group/user.group.permission.js';
|
||
|
||
export default class user extends table {
|
||
|
||
username = new username();
|
||
email = new email();
|
||
groups = new groups(); // Associate user with groups
|
||
|
||
}
|
||
```
|
||
|
||
### Common Use Case
|
||
|
||
For instance, you might have:
|
||
|
||
* **Visitor**: Can only **read** public information
|
||
* **Member**: Can **read** and **write** content
|
||
* **Admin**: Can perform all actions, including **delete**
|
||
|
||
You can easily enforce these permissions using:
|
||
|
||
```js
|
||
permission() {
|
||
this.allow(groups.visitor, "READ"); // Visitors can read
|
||
this.allow(groups.member, "READ"); // Members can read
|
||
this.allow(groups.member, "WRITE"); // Members can write
|
||
this.allow(groups.admin, "READ"); // Admins can read
|
||
this.allow(groups.admin, "WRITE"); // Admins can write
|
||
this.allow(groups.admin, "DELETE"); // Admins can delete
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 2. Scopes: Fine-Grained Permission Control
|
||
|
||
**Scopes** allow you to define permissions not just for entire tables or models, but for **specific fields** or **columns** within those models.
|
||
|
||
For example, a user might be allowed to **read** all the data but only **edit** a certain field, such as a profile description or a specific product attribute.
|
||
|
||
### Example: Scope-Based Permissions
|
||
|
||
```js
|
||
permission() {
|
||
// Allow "member" group to read all users but only update email
|
||
this.allow(groups.member, "READ");
|
||
this.allow(groups.member, "WRITE", "email"); // Allow update on email only
|
||
this.allow(groups.admin, "READ");
|
||
this.allow(groups.admin, "WRITE");
|
||
this.allow(groups.admin, "DELETE");
|
||
}
|
||
```
|
||
|
||
In this example:
|
||
|
||
* **Members** can **read** all data but only **update** the `email` field.
|
||
* **Admins** have full access (can **read**, **write**, and **delete** all fields).
|
||
|
||
You can also control **views** or **actions** like **deleting** based on a particular column or resource.
|
||
|
||
---
|
||
|
||
## 3. Authorization Rules: Controlling Access
|
||
|
||
**Authorization rules** are how you declare which groups have what types of access to your tables, fields, or methods. These rules govern **what actions** a group can perform on **what objects**.
|
||
|
||
You can define rules for specific actions such as:
|
||
|
||
* **READ**: View data
|
||
* **WRITE**: Modify data
|
||
* **DELETE**: Remove data
|
||
|
||
Each object can implement an associated **`permission()`** method to specify which group can perform what action on the object.
|
||
|
||
### Example: Implementing Authorization Rules
|
||
|
||
```js
|
||
export default class news extends table {
|
||
|
||
title = new title();
|
||
body = new body();
|
||
|
||
permission() {
|
||
this.allow(groups.visitor, "READ"); // Visitors can read the news
|
||
this.allow(groups.member, "WRITE"); // Members can write/edit news
|
||
this.allow(groups.admin, "READ"); // Admins can read
|
||
this.allow(groups.admin, "WRITE"); // Admins can write
|
||
this.allow(groups.admin, "DELETE"); // Admins can delete
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 4. Implementing Permissions in `node` Methods
|
||
|
||
In addition to controlling UI elements like columns, you may want to enforce permissions when executing actions on the server (such as creating, updating, or deleting records). This is where **manual permission checks** come into play.
|
||
|
||
### Example: Using Permissions in `node` Methods
|
||
|
||
```js
|
||
node async deleteRow(client) {
|
||
const user = client.user;
|
||
|
||
// Check if the user has permission to delete
|
||
if (!user.hasPermission("DELETE_NEWS")) {
|
||
throw new Error("Permission denied: User cannot delete");
|
||
}
|
||
|
||
this.delete(); // Perform the delete action
|
||
}
|
||
```
|
||
|
||
In this example, the `deleteRow` method checks whether the **current user** has permission to delete the record. If they do not, it throws an error and prevents the action.
|
||
|
||
---
|
||
|
||
## 5. Permissions with Collections
|
||
|
||
Since collections may contain multiple rows (or objects), you may also need to control access at the **collection level**. This allows you to define permissions that apply across the entire dataset.
|
||
|
||
### Example: Permissions for Collection
|
||
|
||
```js
|
||
export default class newsListTableBody extends renderCollection, gridViewBody {
|
||
|
||
permission() {
|
||
this.allow(groups.visitor, "READ"); // Visitors can read all news in the collection
|
||
this.allow(groups.member, "WRITE"); // Members can write new news items
|
||
this.allow(groups.admin, "DELETE"); // Admins can delete news items
|
||
}
|
||
}
|
||
```
|
||
|
||
This ensures that each row in the collection respects the user’s permissions when they try to **view**, **create**, **update**, or **delete** entries.
|
||
|
||
---
|
||
|
||
## 6. Combining Permissions with UI
|
||
|
||
In Unify, you **don't** have to manually manage every UI element (such as showing or hiding a button) based on permissions. You can use the `permission()` method to dynamically control UI elements' visibility and accessibility by the roles assigned.
|
||
|
||
For instance:
|
||
|
||
```js
|
||
node async click() {
|
||
if (this.user.hasPermission("EDIT_NEWS")) {
|
||
this.showEditForm();
|
||
} else {
|
||
throw new Error("Permission denied: Cannot edit news");
|
||
}
|
||
}
|
||
```
|
||
|
||
You can pair the **permissions check** with UI changes to ensure users can only interact with elements they are authorized to use.
|
||
|
||
---
|
||
|
||
## 7. Custom Authorization Logic
|
||
|
||
You can also write custom authorization logic, such as role hierarchies (where one group has broader permissions than another).
|
||
|
||
### Example: Custom Authorization
|
||
|
||
```js
|
||
node async deleteRow(client) {
|
||
const user = client.user;
|
||
|
||
// Only admin or user who created the news can delete it
|
||
if (!(user.hasPermission("DELETE_NEWS") || this.createdBy === user.id)) {
|
||
throw new Error("Permission denied: User cannot delete this news item");
|
||
}
|
||
|
||
this.delete(); // Proceed to delete if authorized
|
||
}
|
||
```
|
||
|
||
This custom rule checks whether the **current user** is an **admin** or the **creator** of the news item before allowing them to delete it.
|
||
|
||
---
|
||
|
||
## Summary of Permissions System
|
||
|
||
| Element | Description |
|
||
| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
|
||
| **Groups** | Roles that define the access level of a user (e.g., Admin, Member, Visitor) |
|
||
| **Scopes** | Granular permissions tied to specific fields, columns, or actions within a model |
|
||
| **Authorization Rules** | Methods (`permission()`) where groups are assigned specific actions (READ, WRITE, DELETE) for objects, fields, or collections |
|
||
| **Custom Logic** | Developers can write custom authorization logic for complex rules like ownership or hierarchical access |
|
||
|
||
Unify's permission system is flexible, allowing developers to define, check, and enforce rules throughout the application — from **UI visibility** to **backend operations** like SQL queries and method executions.
|
||
|
||
|