87 lines
1.9 KiB
Markdown
87 lines
1.9 KiB
Markdown
**`tutorials/03-server-modules-security.md`**
|
||
|
||
````markdown
|
||
# 03 — Server Modules & Security
|
||
|
||
## Roles & Helper
|
||
```python
|
||
import anvil.server
|
||
from anvil import users, secrets
|
||
|
||
ROLES = {"viewer","editor","admin"}
|
||
|
||
def require_role(*roles):
|
||
u = users.get_user()
|
||
if not u: raise PermissionError("Login required")
|
||
if not set(roles).intersection(set(u.get('roles', []))):
|
||
raise PermissionError("Insufficient role")
|
||
````
|
||
|
||
## Validated Callable
|
||
|
||
```python
|
||
@anvil.server.callable
|
||
def secure_greet(name):
|
||
name = (name or "").strip()
|
||
if not (1 <= len(name) <= 64): raise ValueError("Bad name")
|
||
return f"Top-secret hello, {name}"
|
||
```
|
||
|
||
## Secrets + Fake External
|
||
|
||
```python
|
||
API_KEY = secrets.get_secret('DEMO_API_KEY') # set in Anvil
|
||
```
|
||
|
||
## Simple Rate Limit (per user)
|
||
|
||
Use a module-level dict `{user_id: [timestamps...]}`; trim to last 60s, allow ≤5.
|
||
|
||
## Client UX
|
||
|
||
* Try/catch PermissionError → Notification("You need editor role").
|
||
* Disable button while awaiting server.
|
||
|
||
````
|
||
|
||
**`tutorials/04-uplink-file-hash.md`**
|
||
```markdown
|
||
# 04 — Uplink: Local File Hash
|
||
|
||
## Uplink Script (local)
|
||
```python
|
||
import anvil.server, hashlib
|
||
@anvil.server.callable("hash_file")
|
||
def hash_file(buffer):
|
||
h = hashlib.sha256(buffer.get_bytes())
|
||
return h.hexdigest()
|
||
anvil.server.connect("YOUR-UPLINK-KEY")
|
||
anvil.server.wait_forever()
|
||
````
|
||
|
||
## Client
|
||
|
||
* FileLoader → `file_loader_1_change`: call `hash_file` with the Media object.
|
||
* Show result; if timeout/conn error → “Uplink offline”.
|
||
|
||
````
|
||
|
||
**`tutorials/05-auth-roles-ui.md`**
|
||
```markdown
|
||
# 05 — Auth: Users + Roles + UI Gating
|
||
|
||
## Setup
|
||
Enable Users service. Add roles to users (e.g., `editor`, `admin`).
|
||
|
||
## Server
|
||
Use `require_role` from Tutorial 03 to gate `dangerous_action`.
|
||
|
||
## Client
|
||
- Add Login/Logout buttons.
|
||
- Show current user + roles.
|
||
- Hide/show editor-only actions via `component.visible`.
|
||
|
||
## Demo Flow
|
||
- Viewer logs in → can’t see editor actions.
|
||
- Editor logs in → sees & runs gated action.
|
||
```` |