First commit
This commit is contained in:
215
Permissions.md
Normal file
215
Permissions.md
Normal file
@@ -0,0 +1,215 @@
|
||||
|
||||
# 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.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user