diff --git a/diary_family/settings.py b/diary_family/settings.py index b455a2a..286ddec 100644 --- a/diary_family/settings.py +++ b/diary_family/settings.py @@ -198,79 +198,91 @@ FILE_UPLOAD_MAX_MEMORY_SIZE = 524288000 CELERY_BROKER_URL = 'redis://:xjjq1234!@localhost:6379/0' CELERY_RESULT_BACKEND = 'redis://:xjjq1234!@localhost:6379/0' +import sys + +_is_linux = sys.platform == 'linux' + +_syslog_handler = { + 'level': 'WARNING', + 'class': 'logging.handlers.SysLogHandler', + 'address': '/dev/log', + 'facility': 'local0', + 'formatter': 'syslog', +} if _is_linux else { + 'level': 'WARNING', + 'class': 'logging.handlers.RotatingFileHandler', + 'filename': str(LOG_DIR / 'syslog.log'), + 'maxBytes': 1024 * 1024 * 50, + 'backupCount': 5, + 'formatter': 'standard', + 'encoding': 'utf-8', +} + LOGGING = { 'version': 1, - 'disable_existing_loggers': False, # 不关闭已存在的日志器 + 'disable_existing_loggers': False, 'formatters': { - 'standard': { # 统一的标准日志格式 + 'standard': { 'format': '[%(asctime)s] [%(levelname)s] [%(process)d] [%(module)s] %(message)s', 'datefmt': '%Y-%m-%d %H:%M:%S' }, - 'syslog': { # syslog格式(用于fail2ban检测) + 'syslog': { 'format': '%(name)s: %(levelname)s %(message)s' }, }, 'handlers': { - 'file': { # 日志写入文件的处理器 - 'level': 'INFO', # 日志级别:INFO及以上都记录(ERROR/WARNING/INFO) - 'class': 'logging.handlers.RotatingFileHandler', # 日志轮转,防止文件过大 - # ✅ 核心:pathlib对象转字符串,logging只接收字符串路径,必转! + 'file': { + 'level': 'INFO', + 'class': 'logging.handlers.RotatingFileHandler', 'filename': str(LOG_DIR / 'all_in_one.log'), - 'maxBytes': 1024 * 1024 * 100, # 单个日志文件最大100MB - 'backupCount': 10, # 最多保留10个日志备份 - 'formatter': 'standard', # 使用上面定义的统一格式 - 'encoding': 'utf-8', # 编码,防止中文乱码 + 'maxBytes': 1024 * 1024 * 100, + 'backupCount': 10, + 'formatter': 'standard', + 'encoding': 'utf-8', }, - 'console': { # 兼容控制台输出(开发调试用,不影响生产) + 'console': { 'level': 'INFO', 'class': 'logging.StreamHandler', 'formatter': 'standard' }, - 'syslog': { # syslog处理器(用于fail2ban检测登录失败) - 'level': 'WARNING', - 'class': 'logging.handlers.SysLogHandler', - 'address': '/dev/log', # Linux系统日志socket - 'facility': 'local0', - 'formatter': 'syslog', - }, - 'auth_file': { # 认证日志文件处理器(备选方案) + 'syslog': _syslog_handler, + 'auth_file': { 'level': 'WARNING', 'class': 'logging.handlers.RotatingFileHandler', 'filename': str(LOG_DIR / 'auth.log'), - 'maxBytes': 1024 * 1024 * 50, # 50MB + 'maxBytes': 1024 * 1024 * 50, 'backupCount': 5, 'formatter': 'standard', 'encoding': 'utf-8', }, }, - # 所有日志器配置和原配置完全一致,无需任何修改 'loggers': { - 'django': { # Django核心日志 + 'django': { 'handlers': ['file'], 'level': 'INFO', 'propagate': True, }, - 'django.request': { # Django的请求日志 + 'django.request': { 'handlers': ['file'], 'level': 'INFO', 'propagate': True, }, - 'django.security.login': { # 登录安全日志(用于fail2ban) + 'django.security.login': { 'handlers': ['syslog', 'auth_file'], 'level': 'WARNING', 'propagate': False, }, - 'celery': { # Celery客户端日志(Django中提交任务的日志) + 'celery': { 'handlers': ['file'], 'level': 'INFO', 'propagate': True, }, - 'utils.tasks': { # Celery邮件任务模块 + 'utils.tasks': { 'handlers': ['file'], 'level': 'INFO', 'propagate': True, }, - 'utils.email_utils': { # 邮件配置模块 + 'utils.email_utils': { 'handlers': ['file'], 'level': 'INFO', 'propagate': True, diff --git a/docs/superpowers/specs/2026-06-07-api-token-auth-design.md b/docs/superpowers/specs/2026-06-07-api-token-auth-design.md new file mode 100644 index 0000000..105c33f --- /dev/null +++ b/docs/superpowers/specs/2026-06-07-api-token-auth-design.md @@ -0,0 +1,73 @@ +# API Token 鉴权与数据写入接口设计 + +## 概述 + +为家庭日报系统增加 Token 鉴权机制,并通过 API 支持外部写入阅读记录、感悟记录、今日计划。 + +## Token 鉴权 + +- Token 存储在 `settings.py` 的 `API_TOKEN` 配置项中 +- 请求需携带 `Authorization: Bearer ` 头 +- 新建 `@require_api_token` 装饰器统一校验,校验失败返回 401 +- 已有 API(`api_submit_summary`、`api_temp_upload`)同步加上鉴权(破坏性变更,需评估影响) + +## 新增 API 端点 + +所有端点均为 POST,支持 `application/json` 和 `multipart/form-data`(文件上传场景)。统一返回格式: + +```json +{"success": true/false, "message": "...", "id": ...} +``` + +### 1. POST /api/v1/insight/submit/ - 写入感悟记录 + +| 字段 | 类型 | 必填 | 说明 | +|------|------|------|------| +| content | string | 是 | 感悟内容 | +| speaker | string | 是 | 发言人姓名,匹配 FamilyMember.name | +| date | string | 否 | 日期 YYYY-MM-DD,默认今天 | +| file | file | 否 | 附件 | + +### 2. POST /api/v1/reading/submit/ - 写入阅读记录 + +| 字段 | 类型 | 必填 | 说明 | +|------|------|------|------| +| type | string | 是 | 阅读类型,匹配 ReadingType.name | +| title | string | 是 | 标题 | +| source | string | 否 | 来源 | +| progress | string | 否 | 进度 | +| note | string | 否 | 阅读笔记 | +| date | string | 否 | 日期 YYYY-MM-DD,默认今天 | +| file | file | 否 | 附件 | + +### 3. POST /api/v1/plan/submit/ - 写入今日计划 + +| 字段 | 类型 | 必填 | 说明 | +|------|------|------|------| +| content | string | 是 | 计划内容 | +| speaker | string | 否 | 发言人,默认"机器人" | +| priority | string | 否 | 优先级,匹配 Priority.name,默认"中" | +| type | string | 否 | 类型,匹配 PlanType.name,默认"其他" | +| status | string | 否 | 状态,匹配 Status.name,默认"未开始" | +| date | string | 否 | 日期 YYYY-MM-DD,默认今天 | + +## 实现范围 + +- `diary_family/settings.py`:新增 `API_TOKEN` 配置 +- `core/views.py`:新增 `require_api_token` 装饰器、3 个 API 视图函数 +- `core/urls.py`:新增 3 条路由 +- 不引入 DRF,沿用项目现有 JsonResponse + 函数视图模式 +- 不涉及数据库迁移 + +## 错误处理 + +- 401:Token 缺失或错误 +- 400:必填字段缺失、外键匹配失败 +- 405:非 POST 请求 +- 500:服务器内部错误 +- 所有错误统一返回 `{"success": false, "message": "错误描述"}` + +## 向后兼容 + +- 已有 Web 页面功能不受影响 +- 已有 API 端点加上 Token 鉴权(需同步更新调用方)