feat: multi-tenant workspace isolation, RBAC, sidebar nav, billing, and Android enhancements
- Backend: workspace_id isolation for 14 model tables + safe migration/backfill - Backend: RBAC system with 4 roles and 23 permissions, seeded on startup - Backend: workspace admin endpoints (list/manage all workspaces) - Backend: admin user management API (CRUD, reset password) - Backend: billing API with subscription plans, usage tracking, rate limiting - Backend: fix system_logs.py UNION query and wrong column references - Backend: WebSocket JWT auth and workspace enforcement - Frontend: sidebar navigation replacing top dropdown menu - Frontend: user management page (Users.vue) for admins - Frontend: enhanced Workspaces.vue with admin table view - Frontend: workspace RBAC computed properties in user store - Android: agent marketplace, billing/subscription UI, onboarding wizard - Android: phone login, analytics tracker, crash handler, network diagnostics - Android: splash screen, encrypted token storage, app update enhancements - Docs: multi-tenant RBAC guide with 8 sections and role-permission matrix Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,7 @@ from fastapi import APIRouter, WebSocket, WebSocketDisconnect, Depends, HTTPExce
|
||||
from sqlalchemy.orm import Session
|
||||
from app.core.database import get_db, SessionLocal
|
||||
from app.models.workflow import Workflow
|
||||
from app.models.workspace import WorkspaceMembership
|
||||
from app.api.auth import get_current_user
|
||||
from app.models.user import User
|
||||
from app.websocket.collaboration_manager import collaboration_manager
|
||||
@@ -79,6 +80,25 @@ async def websocket_collaboration(
|
||||
await websocket.close(code=status.WS_1008_POLICY_VIOLATION, reason="工作流不存在")
|
||||
return
|
||||
|
||||
# 检查 workspace 成员资格
|
||||
ws_id = payload.get("ws", "")
|
||||
if ws_id and user.role != "admin":
|
||||
membership = (
|
||||
db.query(WorkspaceMembership)
|
||||
.filter(
|
||||
WorkspaceMembership.workspace_id == ws_id,
|
||||
WorkspaceMembership.user_id == user.id,
|
||||
)
|
||||
.first()
|
||||
)
|
||||
if not membership:
|
||||
await websocket.close(code=status.WS_1008_POLICY_VIOLATION, reason="无权访问此工作区")
|
||||
return
|
||||
# 验证 workflow 属于该 workspace
|
||||
if workflow.workspace_id and workflow.workspace_id != ws_id:
|
||||
await websocket.close(code=status.WS_1008_POLICY_VIOLATION, reason="无权编辑此工作流")
|
||||
return
|
||||
|
||||
# 检查权限(只有工作流所有者可以协作编辑,或者未来可以扩展权限)
|
||||
# 暂时只允许所有者编辑
|
||||
if workflow.user_id != user.id:
|
||||
|
||||
Reference in New Issue
Block a user