diff --git a/api/account_manager.py b/api/account_manager.py index 5a6a2ed..0a7cbf0 100755 --- a/api/account_manager.py +++ b/api/account_manager.py @@ -7,6 +7,7 @@ import logging from datetime import datetime, timezone import psycopg2.extras from database import get_db_cursor, execute_query, execute_update +from tenant_manager import TenantManager # Import TenantManager for tenant operations # 配置日志 logger = logging.getLogger(__name__) @@ -65,6 +66,26 @@ class AccountManager: cursor.connection.commit() logger.info(f"用户 {username} 邮箱 {email} 注册成功!") + + # 创建租户并关联角色 + try: + # 创建租户(租户名为"账号名's Workspace") + tenant_name = f"{username}'s Workspace" + tenant_id = TenantManager.create_tenant(tenant_name) + + # 关联新账号为自建租户的owner + AccountManager.associate_with_tenant(result[0], tenant_id, "owner") + + # 关联新账号为ucas's Workspace的normal角色 + ucas_tenant = TenantManager.get_tenant_by_name("ucas's Workspace") + if ucas_tenant: + AccountManager.associate_with_tenant(result[0], ucas_tenant['id'], "normal") + else: + logger.warning("ucas's Workspace not found - skipping normal role association") + except Exception as e: + logger.error(f"租户创建或关联失败: {e}") + # Continue even if tenant operations fail since account creation succeeded + return { "id": result[0], "username": result[1], @@ -289,11 +310,14 @@ class AccountManager: def get_account_tenants(account_id): """获取账户关联的所有租户""" try: + # 处理account_id可能是UUID对象或字符串的情况 + account_id_str = str(account_id) if hasattr(account_id, 'hex') else account_id + # 验证account_id是否为有效UUID try: - uuid.UUID(account_id) + uuid.UUID(account_id_str) except ValueError: - logger.error(f"无效的account_id格式: {account_id}") + logger.error(f"无效的account_id格式: {account_id_str}") return [] query = """ @@ -302,7 +326,7 @@ class AccountManager: JOIN tenant_account_joins j ON t.id = j.tenant_id WHERE j.account_id = %s::uuid; """ - tenants = execute_query(query, (account_id,)) + tenants = execute_query(query, (account_id_str,)) if not tenants: logger.info(f"账号 {account_id} 未关联任何租户") return [] diff --git a/api/app.py b/api/app.py index e6c7d41..8b67d02 100755 --- a/api/app.py +++ b/api/app.py @@ -256,6 +256,21 @@ async def refresh_token(current_user: dict = Depends(get_current_user)): return {"access_token": access_token, "token_type": "bearer"} # 账户管理路由组 +@app.post("/api/accounts/") +async def create_account(account: AccountCreate): + """创建后台管理账户""" + try: + user = backend_account_manager.create_account(account.username, account.email, account.password) + return { + "user_id": str(user["id"]), + "username": user["username"], + "email": user["email"], + "created_at": user["created_at"] + } + except Exception as e: + logger.error(f"创建后台账户失败: {e}") + raise HTTPException(status_code=400, detail="创建后台账户失败") + @app.post("/api/dify_accounts/") async def create_dify_account(account: AccountCreate): """创建Dify账户""" diff --git a/api/privkeys/7136c592-e061-4875-aa9b-707f1efcf4f8/private.pem b/api/privkeys/7136c592-e061-4875-aa9b-707f1efcf4f8/private.pem new file mode 100644 index 0000000..0bd72b0 --- /dev/null +++ b/api/privkeys/7136c592-e061-4875-aa9b-707f1efcf4f8/private.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAvRzEAE/Cbm+QKTqGQ5Xry+W60kTJeIeoQMb8G374PcbTxdPe +0hURUaIH/h7jQ1rhDkNvkaBXC26v0q6ZkCBt89i4TopWCxewVzXb18DAcUswW2z2 +qQs70ssZqpSIn8sQbKfdZn20CD8C1Exkt18uI01VquWqMB30iwZvK8Wly94jm3WC +6xiqnItOz64Y+prOQFhLr0trvoYEf0aKOAnrJr5qeOP6/XnxdF/bHJwOXCU0uFHA +8RXHp58O60fDEZctdSTp9iUQeZidSXS0p3B85NRj/Y2rd/UOEiQ9Sj+DSXg0knXk +CnYiLCeMBpV88bWyCwopRn3Im0haxzVrp9UYVQIDAQABAoIBAAuiuHXjHRhvFCn6 +ktuXtDFlyiU5MZg76ItLyE6SH7NVXMmq6+Z11gygG+kefLyJMUMPvSPy/0gRyw77 +H9xb/R09dAxJELA6szvlHB4Imw6dd1/jXW3bO2wQg7IY1NXYHa5BydU43hnfyUxy +Atm8KSTnk4zMorhhL3RaX1QMeNNelXRzddzm82u1A/mItIMwyu3b3RXrDjIB/VsS +VtY9C1hiXhcWvZdVcRMTRSQt4nbh7ap1QQG1oCHQKBDwBH4rryZHXioKBdKdJOvJ +/1rNtvwWmUtsUwxVNDQ0GnQQlRhg4QoWoEvL9PzMqEEx/Oix2OPEZMa9ePJjUWoj +j0udMkUCgYEA7YrwB/7ASDrNNC2x6dZvNHFAz5Ng9IDqjdBu+u6V61Aq5whoJFDh +ysmywbSaz5NiVtTltr1wggkmWZJKvCLq3CJ+eRm0UfSAsWzeyeOii1+7eazW5zzp +0PpIGdhNBoQf9jo6hn84iyCnxaehyTPDH+0HecFmYu2xyqGwPvFCqfMCgYEAy856 +tbXM/TSeO5GVX/giJ6OzebXcyannbyqeTOgSZ3wlm9pTtsyRhcIfjV4/VjnDkpby +WTPsQqDjCQnWD6kPJXSwRjxQlhoT84FnDf3TtogxOkPUQgp7TRZRFPAy9WtisTyY +EvZefWllw1U5G5WQclBLk4jtWLF8gPG3cya+PpcCgYAGkkJjpjuBhAbrO5xhYKpA +5CUr2OLkwLA8bhiz3mfNU7FsJMJkxswIRR4p16o0tdoRluAn9wOmxUQHVFG29KxU +nKutA/YGEmKBBgb/xMlZW7OfARYM3ZWGT3YxKNewp3UO5bt6vwg8aRHbGPET1NfA +CVmcl6oScIrrlR+ADkKO2wKBgFE7HeuY53gwZbTmZLwYgTx9YcZr9vEl2AmV2fxb +LyKx96dz0JP2WzYN1leZLfNnGI0vvq5RJKS1zWfH1NrvDgtmw+9qkNAS2sreU73e +4mhJRh2r9UjRNq3V7EFFL3pj77UmqpI8QhMIVDgTmqxk42q8mDLYi4kjTLV0IiMy +WPdHAoGBAJkJAhQ1JGSUAY+3QAKBWre8QwabKZdZIzDFq9DdQfnwiHkluueVUI63 +YY5U+wbff0dIAPBpeFGap56XYN8qy3/i6UkRNTTYji5kj6XqVWbyn2xU1IX8/KcC +7AqeEsg04ArqGP0eDAw3gfSe4fgJ5Zoc5ZOkARcb/ajMJi+zA2+W +-----END RSA PRIVATE KEY----- diff --git a/api/privkeys/86220f3c-9e87-4a75-85f6-39fe38067858/private.pem b/api/privkeys/86220f3c-9e87-4a75-85f6-39fe38067858/private.pem new file mode 100644 index 0000000..058b8ec --- /dev/null +++ b/api/privkeys/86220f3c-9e87-4a75-85f6-39fe38067858/private.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEA6GsVZmXAF+XkytRj9c+5tJP2YlWdYLQMo0HXfprVKobLUI5N ++VMrCSreTCARTpsr2KtPV21zSgwVsRzA3zx9RgnAvHzDkJZtkSS1OHGKkA2CAU2T +bJmpZWDEw5L/wOxx0QKA0tWBZzlWvRtXQjGqte/yNYF18TuxCOty6cIPUEQlVcYq +QCwIeDfxGS94GI5ibwynvp7A8QfocR7DxYUZQdo8RSOlBz7d5ra/KVpIRb7I6fsV +4U4qEYsx2GFFXZeZ6HWH7a+deC7Selv9Eycw9cvERWLQVE+FtGyDygbTHpwG7lPl +8D9Yaf2NkXgibsxqHroK6OKyHIr0CkjlxfX1bQIDAQABAoIBACBSVAWLfO1V4T17 +z/LtUmwUb505Psul/mPt0iQfMCnb2QZ448saj8+UkJmRlBaUacKWAFCuPew8Rf/9 +ea0R4nINBSqxRxkiclZO/oy87YIe/sdjnG7r56zbikGQfdS8jQ9+A6BOZNKQHMnr +tXTVJ2Jp3gsm19oWbQZKiA6OGEcXDyikRVipDoavDPBGoTBniJzUNwqD+JyasqdX +QoUIqyJPLLTvXNN6pij8MnK+N86RccEVHdd/NdCDUGyh9ej4vs0dkg8BLTT+3fuw +GR6WSwxZ7qFWl7PD0NhcrJfVQo2X1JNHm4BZFo5kNTJiWkKX+uqEp5QNAZmcXXXK +N6owt9kCgYEA9vBZAE6JKvKBj+wNWeAvUGI/W5KTbYuk8NbPFoYzsqFaseewr0ei +Iq4yzp31fmbIBbyx3iYEIuW2sdxMTEg9ZLi1yqh4qxn3aOhN0/dLkAFZlnBNsJVA +izNsdFDtwy9EIT8vg4Tl1byC+ZzvT2cpP5PYVF4auD1DVUP3Zxet6wMCgYEA8PJV +y18O6smWJPkgDfS2rbUHnP2dBJ6JznrauDGTzDlnd9LNL/sQBG4ZN/nDbo+M2++w +84PeaWB+IQvpweQfZYC/CEA8gJqpQZzlL0TiRJTOAFlm45IEkY9IY9ZM2M0QfbmW +Alt9uCxOQ/+O0TSg7s/hJgjFO7HVU1L+0TGc+s8CgYEA1vm6obe9VnQ0MvVPUjUH +O7Wsbq4WRsHRYBHBy1wd2Z768/I+MPntvr9kX9fIBri33ba+KiVyaGcPO5wLmEUz +nWHocXtlQZ+jceL7DlM1pzJlqcAvAlGNFSI5grGJq+iUKVV2qcqixAYPB/uFotyu +Xjj5lcku/cHnwm0fDtLgh70CgYBeIg8quSSWzdL+9uVzDlwgWU10JBEoMNgd9xlk +RNo9O2AVDCJl0GxdjrYDjGyx0RtzAZ3cRXSrLquYNZNJ0NoDSd1YV+BLTiE6JRXU +9dCAgrJIqKTt26o1RAlAGAVF3jfHJq5YlW30ejrJjho52ZnWMxj/RwXnYH67Yv1y +tTNjOQKBgH57/cRMpvuQ/kuLNYu1IS+EEZJ5WlDjEC0lmM2E54+Lb4D1UBMj+Y7V +EZa9r+UQYm5DnsD4BQjiI1PWY/Iu39Cq3hlkxitOcTOds307xHKbivXancdwlwwx +G+K1nGpNnAHSYCf+qaGdQgfG1LU9REKeLiPkIyt2zOtk6tZ4hmNq +-----END RSA PRIVATE KEY----- diff --git a/docs/api/README.md b/docs/api/README.md new file mode 100644 index 0000000..c347cb8 --- /dev/null +++ b/docs/api/README.md @@ -0,0 +1,54 @@ +# Dify Admin API Documentation + +## Overview +This documentation covers the core API modules of the Dify Admin system. Each module provides specific functionality for managing the administration platform. + +## Module Documentation + +### [Account Management](account_manager.md) +- User account creation and management +- Password hashing and verification +- Tenant association + +### [Tenant Management](tenant_manager.md) +- Workspace/tenant creation +- RSA key pair generation +- Tenant search and retrieval + +### [Model Management](model_manager.md) +- AI model configuration +- Model encryption and storage +- Bulk operations + +### [Provider Management](provider_manager.md) +- AI service provider management +- API key encryption +- Provider configuration + +### [Database Operations](database.md) +- Connection pooling +- SQL execution helpers +- Database initialization + +### [Operation Logging](operation_logger.md) +- Audit trail recording +- Log querying +- Log maintenance + +### [Encryption Services](encryption.md) +- Hybrid encryption (RSA + AES) +- Key management +- API key protection + +## Getting Started +To use these APIs, import the required module and instantiate the appropriate class: + +```python +from api.account_manager import AccountManager +account_mgr = AccountManager() +``` + +## Security Notes +- All sensitive operations use encryption +- API keys are never stored in plaintext +- Detailed logging for audit purposes diff --git a/docs/api/account_manager.md b/docs/api/account_manager.md new file mode 100644 index 0000000..3f9c87e --- /dev/null +++ b/docs/api/account_manager.md @@ -0,0 +1,97 @@ +# Account Manager API Documentation + +## Overview +The `AccountManager` class provides functionality for managing user accounts, including: +- Account creation and authentication +- Password management (hashing, verification, reset) +- Account search and retrieval +- Tenant association management + +## Class Methods + +### `hash_password(password, salt=None)` +Generates a hashed password and salt for secure storage. + +**Parameters:** +- `password` (str): Plain text password to hash +- `salt` (bytes, optional): Optional salt value. If None, generates new salt. + +**Returns:** +- Tuple of (base64_password_hashed, base64_salt) + +**Example:** +```python +hashed_pw, salt = AccountManager.hash_password("mysecurepassword") +``` + +### `create_account(username, email, password)` +Creates a new user account. + +**Parameters:** +- `username` (str): Unique username +- `email` (str): User email address +- `password` (str): Plain text password + +**Returns:** +- Dictionary with created account details: + ```python + { + "id": UUID, + "username": str, + "email": str, + "created_at": datetime + } + ``` + +### `get_user_by_username(username)` +Retrieves user information by username. + +**Parameters:** +- `username` (str): Username to search for + +**Returns:** +- User dictionary or None if not found + +### `search_accounts(search=None, page=1, page_size=10)` +Searches accounts with pagination. + +**Parameters:** +- `search` (str): Optional search term +- `page` (int): Page number (1-based) +- `page_size` (int): Items per page + +**Returns:** +```python +{ + "data": [user_dicts], + "total": int +} +``` + +### `verify_password(plain_password, hashed_password, salt)` +Verifies a password against stored hash. + +**Parameters:** +- `plain_password` (str): Password to verify +- `hashed_password` (str): Stored password hash +- `salt` (str): Password salt + +**Returns:** +- bool: True if password matches + +### Password Management +- `update_password(username, email, new_password)` +- `reset_password(account_id)` + +### Tenant Association +- `associate_with_tenant(account_id, tenant_id, role, invited_by, current)` +- `get_tenant_accounts(tenant_id)` +- `get_account_tenants(account_id)` + +## Error Handling +All methods raise exceptions on failure and log errors using the module logger. + +## Security Notes +- Uses PBKDF2 with SHA-256 for password hashing +- Generates random salts for each password +- All sensitive operations are logged diff --git a/docs/api/database.md b/docs/api/database.md new file mode 100644 index 0000000..1f29e83 --- /dev/null +++ b/docs/api/database.md @@ -0,0 +1,81 @@ +# Database API Documentation + +## Overview +The database module provides database connection management and basic operations for both PostgreSQL and SQLite databases. Key features include: +- Connection pooling for PostgreSQL +- Context managers for safe connection handling +- Unified interface for both database types +- SQL execution helpers + +## Connection Management + +### `get_db_connection(db_type='postgres')` +Context manager for database connections. + +**Parameters:** +- `db_type`: 'postgres' or 'sqlite' (default: 'postgres') + +**Usage:** +```python +with get_db_connection() as conn: + # Use connection +``` + +### `get_db_cursor(cursor_factory=None, db_type='postgres')` +Context manager for database cursors with automatic commit/rollback. + +**Parameters:** +- `cursor_factory`: Optional cursor factory (e.g., psycopg2.extras.DictCursor) +- `db_type`: 'postgres' or 'sqlite' (default: 'postgres') + +**Usage:** +```python +with get_db_cursor() as cursor: + cursor.execute("SELECT * FROM table") +``` + +## SQL Execution Helpers + +### `execute_query(query, params=None, cursor_factory=None, fetch_one=False, db_type='postgres')` +Executes a query and returns results. + +**Parameters:** +- `query`: SQL query string +- `params`: Query parameters (tuple/dict) +- `cursor_factory`: Optional cursor factory +- `fetch_one`: Return single row if True +- `db_type`: Database type + +**Returns:** +- Query results (list or single row) + +### `execute_update(query, params=None, db_type='postgres')` +Executes an update/insert/delete query. + +**Parameters:** +- `query`: SQL query string +- `params`: Query parameters (tuple/dict) +- `db_type`: Database type + +**Returns:** +- Number of affected rows + +## Initialization + +### `init_sqlite_db()` +Initializes SQLite database tables (api_endpoints, api_logs, api_users, api_operations). + +## Configuration +Module uses configuration from: +- `DB_CONFIG` for PostgreSQL +- `SQLITE_CONFIG` for SQLite + +## Error Handling +- All database operations are wrapped in try/except blocks +- Errors are logged with detailed context +- Connections are automatically returned to pool (PostgreSQL) or closed (SQLite) + +## Best Practices +- Always use context managers (`with` statements) for connections/cursors +- For PostgreSQL, prefer connection pooling for better performance +- For complex transactions, use explicit commit/rollback diff --git a/docs/api/encryption.md b/docs/api/encryption.md new file mode 100644 index 0000000..3e23ac8 --- /dev/null +++ b/docs/api/encryption.md @@ -0,0 +1,51 @@ +# Encryption API Documentation + +## Overview +The `Encryption` class provides cryptographic functions including: +- RSA key pair generation and management +- Hybrid encryption (RSA + AES) +- API key encryption +- Secure key storage + +## Class Methods + +### Key Management +- `load_public_key(public_key_path_or_content)` + - Loads public key from file or content +- `load_private_key(private_key_path)` + - Loads private key from file + +### Encryption/Decryption +- `encrypt(text, public_key)` + - Encrypts text using hybrid RSA+AES approach + - Returns: Encrypted data with "HYBRID:" prefix +- `decrypt(encrypted_text, private_key)` + - Decrypts hybrid encrypted data + - Returns: Original plaintext + +### Specialized Methods +- `encrypt_api_key(public_key_pem, api_key)` + - Encrypts API keys with base64 encoding + - Returns: base64 encoded encrypted key + +## Security Features +- Uses 2048-bit RSA keys +- AES-256 for symmetric encryption +- Random key generation for each operation +- Secure key storage practices +- Detailed error logging + +## Error Handling +- Validates all inputs +- Raises exceptions for invalid operations +- Logs all errors with context + +## Example Usage +```python +# Encrypt data +public_key = Encryption.load_public_key("public.pem") +encrypted = Encryption.encrypt("secret data", public_key) + +# Decrypt data +private_key = Encryption.load_private_key("private.pem") +decrypted = Encryption.decrypt(encrypted, private_key) diff --git a/docs/api/model_manager.md b/docs/api/model_manager.md new file mode 100644 index 0000000..6cf1400 --- /dev/null +++ b/docs/api/model_manager.md @@ -0,0 +1,75 @@ +# Model Manager API Documentation + +## Overview +The `ModelManager` class provides functionality for managing AI models, including: +- Adding models to tenants (both standard and Volc models) +- Removing models +- Querying model information +- Bulk operations for all tenants + +## Class Methods + +### Model Addition +- `add_model_for_tenant(tenant_id, public_key_pem, model_config)` + - Adds a standard model to a tenant + - Encrypts API keys using tenant's public key + - Supports different model types (text-generation, embeddings, etc.) + +- `add_volc_model_for_tenant(tenant_id, public_key_pem, model_config)` + - Adds a Volc engine model to a tenant + - Special handling for Volc-specific parameters + +**Common Parameters:** +- `tenant_id`: Target tenant UUID +- `public_key_pem`: Tenant's public key for encryption +- `model_config`: Dictionary containing model configuration + +**Required Fields in model_config:** +```python +{ + "model_name": str, # Unique model name + "provider_name": str, # Provider identifier + "model_type": str, # Type of model + "api_key": str # API key to encrypt (or volc_api_key for Volc models) +} +``` + +### Bulk Operations +- `add_models_for_all_tenants(config_path)` +- `add_volc_models_for_all_tenants(config_path)` +- `add_models_for_tenant(tenant_name, config_path)` +- `add_volc_models_for_tenant(tenant_name, config_path)` + +### Model Removal +- `delete_model_for_tenant(tenant_id, model_name)` +- `delete_models_for_tenant(tenant_id)` +- `delete_specific_model_for_all_tenants(model_name)` + +### Query Methods +- `get_tenant_models(tenant_id)` + - Returns all models for a tenant + - Format: + ```python + { + "tenant_id": str, + "models": [{ + "id": str, + "provider_name": str, + "model_name": str, + "model_type": str, + "encrypted_config": dict, + "is_valid": bool, + "created_at": datetime, + "updated_at": datetime + }] + } + ``` + +## Security Considerations +- All API keys are encrypted using tenant's public key +- Supports different encryption configurations per model type +- Detailed logging of all operations + +## Error Handling +- Raises exceptions for invalid configurations +- Logs all errors with detailed context diff --git a/docs/api/operation_logger.md b/docs/api/operation_logger.md new file mode 100644 index 0000000..a7c9aa6 --- /dev/null +++ b/docs/api/operation_logger.md @@ -0,0 +1,65 @@ +# Operation Logger API Documentation + +## Overview +The `OperationLogger` class provides functionality for recording and managing operation logs, including: +- Logging API operations +- Querying operation logs with filters +- Cleaning up old logs + +## Class Methods + +### `log_operation(user_id, operation_type, endpoint, parameters=None, status="SUCCESS")` +Records an API operation in the database. + +**Parameters:** +- `user_id` (int): ID of the user performing the operation +- `operation_type` (str): Type of operation (e.g., "CREATE", "UPDATE") +- `endpoint` (str): API endpoint accessed +- `parameters` (str, optional): Operation parameters in string format +- `status` (str): Operation status (default: "SUCCESS") + +**Returns:** +- int: ID of the created log record + +**Example:** +```python +logger.log_operation(123, "LOGIN", "/api/auth/login", "username=test", "SUCCESS") +``` + +### `get_operations(user_id=None, start_time=None, end_time=None, limit=100)` +Queries operation logs with optional filters. + +**Parameters:** +- `user_id` (int, optional): Filter by user ID +- `start_time` (datetime, optional): Earliest log time +- `end_time` (datetime, optional): Latest log time +- `limit` (int): Maximum number of logs to return (default: 100) + +**Returns:** +- List of log records with fields: + - id + - user_id + - operation_type + - endpoint + - parameters + - status + - created_at + +### `clean_old_logs(days=30)` +Deletes logs older than specified number of days. + +**Parameters:** +- `days` (int): Delete logs older than this many days (default: 30) + +**Returns:** +- int: Number of logs deleted + +## Error Handling +- Raises `OperationLogError` for all failures +- Detailed error logging through module logger + +## Best Practices +- Log all critical operations for audit trail +- Regularly clean old logs to maintain performance +- Use appropriate status values ("SUCCESS", "FAILED", etc.) +- Include relevant parameters for debugging diff --git a/docs/api/provider_manager.md b/docs/api/provider_manager.md new file mode 100644 index 0000000..9f78358 --- /dev/null +++ b/docs/api/provider_manager.md @@ -0,0 +1,61 @@ +# Provider Manager API Documentation + +## Overview +The `ProviderManager` class provides functionality for managing AI service providers, including: +- Adding providers to tenants +- Removing providers +- Querying provider information +- Bulk operations for all tenants + +## Class Methods + +### Provider Addition +- `add_provider_for_tenant(tenant_id, public_key_pem, provider_config)` + - Adds a provider to a tenant + - Encrypts API keys using tenant's public key + - Supports different provider types + +**Parameters:** +- `tenant_id`: Target tenant UUID +- `public_key_pem`: Tenant's public key for encryption +- `provider_config`: Dictionary containing provider configuration + +**Required Fields in provider_config:** +```python +{ + "provider_name": str, # Unique provider name + "config": dict # Provider configuration including API keys +} +``` + +### Bulk Operations +- `add_providers_for_all_tenants(config_path)` +- `add_providers_for_tenant(tenant_name, config_path)` + +### Provider Removal +- `delete_provider_for_tenant(tenant_id, provider_name)` +- `delete_providers_for_tenant(tenant_id)` + +### Query Methods +- `get_providers_for_tenant(tenant_id)` + - Returns all providers for a tenant + - Format: + ```python + [ + { + "id": str, + "provider_name": str, + "provider_type": str, + "is_valid": bool + } + ] + ``` + +## Security Considerations +- API keys are encrypted using tenant's public key +- Detailed logging of all operations +- Validation of required fields + +## Error Handling +- Raises exceptions for invalid configurations +- Logs all errors with detailed context diff --git a/docs/api/tenant_manager.md b/docs/api/tenant_manager.md new file mode 100644 index 0000000..a8c879c --- /dev/null +++ b/docs/api/tenant_manager.md @@ -0,0 +1,70 @@ +# Tenant Manager API Documentation + +## Overview +The `TenantManager` class provides functionality for managing tenants (workspaces), including: +- Tenant creation with RSA key pair generation +- Key management (generation, storage) +- Tenant search and retrieval + +## Class Methods + +### `generate_rsa_key_pair()` +Generates a new RSA key pair for tenant encryption. + +**Returns:** +- Tuple of (public_key_pem, private_key) + - public_key_pem: PEM formatted public key string + - private_key: RSA private key object + +**Example:** +```python +public_key, private_key = TenantManager.generate_rsa_key_pair() +``` + +### `save_private_key(tenant_id, private_key)` +Securely stores a private key for a tenant. + +**Parameters:** +- `tenant_id` (UUID): Tenant identifier +- `private_key`: RSA private key object + +**Returns:** +- Path to stored private key file + +### `create_tenant(workspace_name)` +Creates a new tenant with cryptographic keys. + +**Parameters:** +- `workspace_name` (str): Name for the new tenant/workspace + +**Returns:** +- UUID of created tenant + +**Process:** +1. Generates RSA key pair +2. Stores private key securely +3. Creates tenant record with public key + +### Query Methods +- `get_tenant_by_name(workspace_name)`: Retrieves tenant by name +- `get_all_tenants()`: Lists all tenants +- `search_tenants(search_term)`: Searches tenants by name + +**Return Format:** +```python +{ + "id": str/UUID, + "name": str, + "encrypt_public_key": str, + "created_at": datetime +} +``` + +## Security Considerations +- Uses 2048-bit RSA keys for encryption +- Private keys stored in secure directory structure +- Public keys stored in database for encryption +- All operations are logged + +## Error Handling +Methods raise exceptions on failure and log errors using the module logger. diff --git a/docs/architecture/overview.md b/docs/architecture/overview.md new file mode 100644 index 0000000..932b0a7 --- /dev/null +++ b/docs/architecture/overview.md @@ -0,0 +1,48 @@ +# Dify Admin System Architecture + +## Overall Architecture +```mermaid +graph TD + A[Frontend] -->|API Calls| B[Backend] + B --> C[Database] + B --> D[External Services] + C --> E[(PostgreSQL)] + C --> F[(SQLite)] +``` + +## Core Components + +### Frontend +- **Framework**: Vue 3 + TypeScript +- **State Management**: Pinia +- **UI Library**: Element Plus +- **Routing**: Vue Router + +### Backend +- **API Services**: + - Account Management + - Tenant Management + - Model Management + - Provider Management +- **Core Modules**: + - Database Access + - Encryption + - Operation Logging + +## Data Flow +1. User actions trigger API calls +2. Backend processes requests with business logic +3. Data persisted to database +4. Responses returned to frontend +5. Frontend updates state and UI + +## Security Architecture +- JWT Authentication +- RSA Encryption for sensitive data +- Role-based Access Control +- Audit logging + +## Deployment +- Frontend: Static hosting (Vite) +- Backend: Containerized microservices +- Database: PostgreSQL (primary), SQLite (logging) diff --git a/docs/web/README.md b/docs/web/README.md new file mode 100644 index 0000000..2643436 --- /dev/null +++ b/docs/web/README.md @@ -0,0 +1,31 @@ +# Web Frontend Documentation + +## Technology Stack +- **Framework**: Vue 3 (Composition API) +- **UI Library**: Element Plus +- **State Management**: Pinia +- **Routing**: Vue Router +- **HTTP Client**: Axios + +## Core Architecture + +### Application Initialization +1. Creates Vue app instance +2. Configures router and store +3. Initializes Element Plus components +4. Checks for existing auth token +5. Mounts to DOM element (#app) + +### Key Files +- `main.ts`: Application entry point +- `App.vue`: Root component +- `router/index.ts`: Route configuration +- `store/index.ts`: State management setup + +## Module Structure +- `api/`: API service layer +- `axios/`: HTTP client configuration +- `router/`: Navigation logic +- `store/`: Global state management +- `utils/`: Helper functions +- `views/`: Page components diff --git a/docs/web/api.md b/docs/web/api.md new file mode 100644 index 0000000..f45a295 --- /dev/null +++ b/docs/web/api.md @@ -0,0 +1,48 @@ +# API Service Documentation + +## Architecture +- **HTTP Client**: Axios with custom wrapper +- **Modular Structure**: Feature-based organization +- **Type Safety**: TypeScript interfaces + +## Auth Module + +### Methods +- `login(data)`: User authentication + - Parameters: `{username, password}` + - Returns: `{access_token}` + - Content-Type: `application/json` + +- `register(formData)`: User registration + - Parameters: FormData + - Returns: `{user_id}` + - Content-Type: `multipart/form-data` + +- `getPublicKey()`: Gets RSA public key + - Returns: Public key string + - Error Handling: Custom error messages + +- `refreshToken()`: Refreshes access token + - Returns: New `{access_token}` + +## Request Wrapper +Located in `axios/service.ts`: +- Base URL configuration +- Request/response interceptors +- Error handling +- Type definitions + +## Type Definitions +Each module has corresponding type definitions: +```typescript +// Example from auth/types.ts +interface LoginParams { + username: string + password: string +} +``` + +## Error Handling +- Custom error messages +- Type-safe error responses +- Console logging for debugging diff --git a/docs/web/router.md b/docs/web/router.md new file mode 100644 index 0000000..53bf8c3 --- /dev/null +++ b/docs/web/router.md @@ -0,0 +1,37 @@ +# Router Documentation + +## Route Configuration + +### Public Routes +- `/login`: Login page +- `/register`: Registration page + +### Authenticated Routes (Nested under Layout) +- `/dashboard`: Main dashboard +- `/user`: User management +- `/account`: Account settings +- `/model`: Model management + +## Route Meta Fields +- `requiresAuth`: Boolean indicating if authentication is required + +## Route Guards +### Authentication Check +1. Checks for `access_token` in localStorage +2. Redirects to `/login` if: + - Route requires auth (`meta.requiresAuth`) + - No valid token found + +## Technical Details +- **Mode**: HTML5 History Mode +- **Component Loading**: Dynamic imports (code splitting) +- **Base Path**: Project root (`/`) + +## Example Usage +```javascript +// Adding a new route +{ + path: 'new-route', + component: () => import('../views/NewRoute.vue'), + meta: { requiresAuth: true } +} diff --git a/docs/web/store.md b/docs/web/store.md new file mode 100644 index 0000000..0d2b196 --- /dev/null +++ b/docs/web/store.md @@ -0,0 +1,36 @@ +# State Management Documentation + +## Architecture +- **Library**: Pinia (Vue 3 recommended state management) +- **Structure**: Modular stores +- **Reactivity**: Composition API style + +## User Store + +### State Properties +- `token`: Authentication token +- `userInfo`: User profile data + +### Methods +- `setToken(token)`: Updates token in store and localStorage +- `setUserInfo(info)`: Updates user profile +- `login(params)`: Handles login flow + - Parameters: `{username, password}` + - Returns: `{access_token}` +- `getUserInfo()`: Returns current user info + +### Persistence +- Token is automatically synced with localStorage +- Uses `utils/storage` helper methods + +## Usage Example +```javascript +import { useUserStore } from '@/store' + +const userStore = useUserStore() + +// Login +await userStore.login({username: 'test', password: '123'}) + +// Get user info +const user = userStore.getUserInfo() diff --git a/web/src/api/account/index.ts b/web/src/api/account/index.ts index a102139..2cde96b 100644 --- a/web/src/api/account/index.ts +++ b/web/src/api/account/index.ts @@ -46,14 +46,19 @@ export const toggleAccountStatus = (id: string) => url: `/api/accounts/${id}/toggle-status` }) -export const createAccount = (data: { username: string }) => +export const createAccount = (data: { username: string; email: string; password?: string }) => request<{ - message: string - account: AccountItem + user_id: string + username: string + email: string + created_at: string }>({ method: 'POST', - url: '/api/accounts', - data + url: '/api/accounts/', + data: { + ...data, + password: data.password || 'TempPassword123!' // Default password + } }) // Dify账号相关API diff --git a/web/src/views/Account/components/CreateAccountDialog.vue b/web/src/views/Account/components/CreateAccountDialog.vue new file mode 100644 index 0000000..f1413a4 --- /dev/null +++ b/web/src/views/Account/components/CreateAccountDialog.vue @@ -0,0 +1,58 @@ + + + diff --git a/web/src/views/Account/components/CreateAccountForm.vue b/web/src/views/Account/components/CreateAccountForm.vue new file mode 100644 index 0000000..68ba960 --- /dev/null +++ b/web/src/views/Account/components/CreateAccountForm.vue @@ -0,0 +1,29 @@ + + + diff --git a/web/src/views/Account/index.vue b/web/src/views/Account/index.vue index d4de586..f6b0979 100644 --- a/web/src/views/Account/index.vue +++ b/web/src/views/Account/index.vue @@ -91,17 +91,20 @@ + +