Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
dc2ce81
feat: 实现 Raindrop.io OAuth2 自动认证系统
foreveryh Aug 30, 2025
1bcf5b8
fix: 调整 Cron 任务以符合 Vercel Hobby 计划限制
foreveryh Aug 31, 2025
5ba2c15
fix: 修复 package.json 中的 JSON 语法错误
foreveryh Aug 31, 2025
9363363
fix: 解决构建时环境变量依赖问题
foreveryh Aug 31, 2025
d5046bc
feat: 添加多存储方案OAuth2认证系统
foreveryh Aug 31, 2025
11cbbcc
feat: 更新API路由以支持动态存储选择
foreveryh Aug 31, 2025
e32c1a3
feat: 更新书签页面使用新认证系统
foreveryh Aug 31, 2025
4874956
docs: 添加OAuth2系统文档和部署指南
foreveryh Aug 31, 2025
462bd0f
feat(auth): implement OAuth2 authentication system with multiple stor…
foreveryh Aug 31, 2025
afc0ac9
feat(api): add OAuth2 authentication API routes
foreveryh Aug 31, 2025
bb769ef
feat(bookmarks): integrate authentication with bookmark fetching
foreveryh Aug 31, 2025
1316843
feat(admin): add OAuth setup admin interface and deployment verification
foreveryh Aug 31, 2025
0739208
chore: fix linting errors and clean up codebase
foreveryh Aug 31, 2025
be4f28d
fix: resolve React Hook usage in workspace easter egg
foreveryh Aug 31, 2025
fbba42e
fix: disable font loading warning in ESLint config
foreveryh Aug 31, 2025
d3c79cc
fix: rename keySequence to keySequenceRef to resolve ESLint unused va…
foreveryh Aug 31, 2025
70e403f
fix: ignore test-*.js files in ESLint configuration
foreveryh Aug 31, 2025
b1c68e8
fix: replace console.log with console.info in test files
foreveryh Aug 31, 2025
000eb20
fix: update CI workflow to checkout PR branch instead of base branch
foreveryh Aug 31, 2025
563d884
fix: change CI workflow from pull_request_target to pull_request
foreveryh Aug 31, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,22 @@ SUPABASE_SERVICE_ROLE_KEY=
NEXT_PUBLIC_SUPABASE_URL=
NEXT_PUBLIC_SUPABASE_ANON_KEY=

// Raindrop
NEXT_PUBLIC_RAINDROP_ACCESS_TOKEN=
// Raindrop OAuth2 配置
RAINDROP_CLIENT_ID=your_raindrop_client_id
RAINDROP_CLIENT_SECRET=your_raindrop_client_secret
RAINDROP_ENCRYPTION_KEY=your_32_character_encryption_key

// 基础URL配置
NEXT_PUBLIC_BASE_URL=https://your-domain.com

// Vercel Cron 安全密钥
CRON_SECRET=your_random_cron_secret

// Vercel KV 配置 (由Vercel自动提供)
KV_URL=
KV_REST_API_URL=
KV_REST_API_TOKEN=
KV_REST_API_READ_ONLY_TOKEN=

// On-Demand Revalidation
NEXT_REVALIDATE_SECRET=
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: CI

on:
pull_request_target:
pull_request:
types:
- opened
- edited
Expand Down
169 changes: 169 additions & 0 deletions OAUTH2_SYSTEM.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
# OAuth2 认证系统实现

## 概述

为了解决 Raindrop.io 书签同步中的 token 过期问题,本项目实现了完整的 OAuth2 自动认证系统,支持多种存储方案,确保无需手动干预即可维持书签数据的持续同步。

## 核心特性

### 🔄 自动 Token 刷新
- **三层刷新机制**:请求时刷新、定时刷新、错误恢复
- **智能过期检测**:提前刷新,避免服务中断
- **失败重试**:自动重试机制,提高可靠性

### 🗄️ 多存储方案支持
1. **Vercel KV**(优先)- 原生云存储,性能最佳
2. **Supabase**(推荐)- 免费可靠,功能完整
3. **环境变量**(备用)- 最简单,适合小规模使用

### 🔐 安全性保障
- **AES-256-GCM 加密**:所有存储的 tokens 都经过军用级加密
- **环境隔离**:敏感信息通过环境变量管理
- **访问控制**:Cron 作业和管理接口都有访问控制

### 🛡️ 容错机制
- **优雅降级**:存储不可用时自动切换到备用方案
- **缓存支持**:减少API调用,提高响应速度
- **错误处理**:完整的错误处理和日志记录

## 技术架构

```
┌─────────────────────┐
│ 前端页面/组件 │
└──────────┬──────────┘
┌──────────▼──────────┐
│ raindrop-with-auth │ ← 统一认证接口
└──────────┬──────────┘
┌──────────▼──────────┐
│ 动态 Token Manager │ ← 自动选择存储方案
└──────────┬──────────┘
┌──────▼──────┐
│ 存储方案选择 │
└──┬──┬───┬───┘
│ │ │
┌───▼┐ │ │
│ KV │ │ │
└────┘ │ │
┌───▼───┐
│Supabase│
└───────┘
┌───▼───┐
│ Env │
│ Vars │
└───────┘
```

## 文件结构

```
src/lib/auth/
├── crypto.js # AES-256 加密/解密工具
├── token-manager.js # Vercel KV 存储实现
├── supabase-token-manager.js # Supabase 存储实现
└── env-token-manager.js # 环境变量存储实现

src/lib/
├── raindrop-with-auth.js # 带认证的 Raindrop API 封装
└── raindrop.js # 原始 API 封装(向后兼容)

src/app/api/
├── auth/raindrop/ # OAuth2 认证端点
│ ├── route.js # 启动认证
│ ├── callback/route.js # 处理回调
│ ├── status/route.js # 检查状态
│ └── clear/route.js # 清除认证
├── bookmarks/route.js # 增强的书签API
└── cron/refresh-tokens/ # 定时刷新任务
└── route.js
```

## API 端点

### OAuth2 认证
- `GET /api/auth/raindrop` - 启动 OAuth 认证流程
- `GET /api/auth/raindrop/callback` - 处理 OAuth 回调
- `GET /api/auth/raindrop/status` - 检查认证状态
- `POST /api/auth/raindrop/clear` - 清除认证信息

### 书签数据
- `GET /api/bookmarks` - 获取所有书签(支持缓存)
- `GET /api/bookmarks?collection=ID&page=N` - 分页获取特定收藏夹

### 系统维护
- `GET /api/cron/refresh-tokens` - 定时刷新 tokens(Cron Job)

## 环境变量配置

### 必需变量(所有方案)
```bash
RAINDROP_CLIENT_ID=xxx # Raindrop.io OAuth Client ID
RAINDROP_CLIENT_SECRET=xxx # Raindrop.io OAuth Client Secret
RAINDROP_ENCRYPTION_KEY=xxx # 32字符加密密钥
NEXT_PUBLIC_BASE_URL=xxx # 应用基础URL
CRON_SECRET=xxx # Cron作业保护密钥
```

### Vercel KV 方案
```bash
KV_REST_API_URL=xxx # Vercel KV REST API URL
KV_REST_API_TOKEN=xxx # Vercel KV REST API Token
```

### Supabase 方案
```bash
NEXT_PUBLIC_SUPABASE_URL=xxx # Supabase 项目 URL
SUPABASE_ANON_KEY=xxx # Supabase Anonymous Key
```

### 环境变量方案
```bash
RAINDROP_ENCRYPTED_REFRESH_TOKEN=xxx # 加密的 Refresh Token
```

## 部署流程

1. **配置 OAuth 应用**(Raindrop.io 开发者控制台)
2. **选择存储方案**(推荐 Supabase)
3. **设置环境变量**(Vercel 项目设置)
4. **部署应用**
5. **完成初始认证**(访问 /admin/oauth-setup)
6. **验证功能**(检查书签页面)

详细步骤请参考 `QUICK_START.md`。

## 监控和维护

### 日志监控
- Vercel 函数日志中可查看认证和刷新状态
- 错误日志包含详细的故障信息

### Token 生命周期
- **Access Token**:1小时有效期,自动刷新
- **Refresh Token**:180天有效期,需要重新认证

### 健康检查
使用 `scripts/verify-deployment.js` 验证系统状态:
```bash
node scripts/verify-deployment.js
```

## 性能优化

- **智能缓存**:2天缓存周期,减少API调用
- **分页支持**:大量数据的高效加载
- **并发控制**:避免API限制和竞态条件
- **错误恢复**:快速从临时故障中恢复

## 安全考虑

- **加密存储**:所有敏感数据都经过AES-256加密
- **最小权限**:只请求必需的API权限
- **访问控制**:管理接口需要适当的认证
- **日志清理**:不在日志中暴露敏感信息

这个系统确保了 Raindrop.io 书签数据的持续可用性,同时提供了灵活的部署选项和强大的容错能力。
127 changes: 127 additions & 0 deletions OAUTH_DEPLOYMENT_GUIDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
# Raindrop.io OAuth2 部署指南

由于 Vercel KV 存储选项在某些账户中不可用,我们提供了三种存储方案供选择:

## 存储方案选择

系统会自动检测可用的存储方案并按优先级选择:

1. **Vercel KV** (优先) - 如果环境变量 `KV_REST_API_URL` 和 `KV_REST_API_TOKEN` 存在
2. **Supabase** (推荐) - 如果环境变量 `NEXT_PUBLIC_SUPABASE_URL` 和 `SUPABASE_ANON_KEY` 存在
3. **环境变量存储** (备用) - 始终可用,但需要手动更新环境变量

## 方案 1: Vercel KV 存储 (如果可用)

### 前置条件
- Vercel 仪表板中 KV 存储选项可见
- Hobby 或 Pro 计划

### 设置步骤
1. 在 Vercel 仪表板中创建 KV 数据库
2. 连接到您的项目
3. 添加以下环境变量:
```bash
RAINDROP_CLIENT_ID=your_client_id_here
RAINDROP_CLIENT_SECRET=your_client_secret_here
RAINDROP_ENCRYPTION_KEY=your_32_character_random_key
NEXT_PUBLIC_BASE_URL=https://me.deeptoai.com
CRON_SECRET=your_random_cron_secret
```

## 方案 2: Supabase 存储 (推荐)

### 前置条件
- Supabase 免费账户
- 创建一个新项目

### 设置步骤

#### 1. 创建 Supabase 项目
1. 访问 [supabase.com](https://supabase.com) 并创建免费账户
2. 创建新项目
3. 记录项目的 URL 和 anon key

#### 2. 设置数据库表
在 Supabase SQL Editor 中运行以下 SQL:
```sql
-- 见 supabase-setup.sql 文件内容
```

#### 3. 添加环境变量到 Vercel
```bash
RAINDROP_CLIENT_ID=your_client_id_here
RAINDROP_CLIENT_SECRET=your_client_secret_here
RAINDROP_ENCRYPTION_KEY=your_32_character_random_key
NEXT_PUBLIC_BASE_URL=https://me.deeptoai.com
CRON_SECRET=your_random_cron_secret
NEXT_PUBLIC_SUPABASE_URL=your_supabase_project_url
SUPABASE_ANON_KEY=your_supabase_anon_key
```

## 方案 3: 环境变量存储

### 特点
- 最简单的设置
- 无需外部数据库
- 需要手动更新 refresh token

### 设置步骤
1. 添加基本环境变量:
```bash
RAINDROP_CLIENT_ID=your_client_id_here
RAINDROP_CLIENT_SECRET=your_client_secret_here
RAINDROP_ENCRYPTION_KEY=your_32_character_random_key
NEXT_PUBLIC_BASE_URL=https://me.deeptoai.com
CRON_SECRET=your_random_cron_secret
```

2. 完成 OAuth 认证后,系统会在控制台输出加密的 refresh token
3. 手动将其添加为环境变量:
```bash
RAINDROP_ENCRYPTED_REFRESH_TOKEN=encrypted_token_from_console
```

## Raindrop.io OAuth 应用设置

无论选择哪种存储方案,都需要设置 Raindrop.io OAuth 应用:

1. 访问 [Raindrop.io 开发者控制台](https://app.raindrop.io/settings/integrations)
2. 创建新的 OAuth 应用
3. 设置回调 URL: `https://me.deeptoai.com/api/auth/raindrop/callback`
4. 记录 Client ID 和 Client Secret

## 初始认证流程

1. 部署应用后,访问: `https://me.deeptoai.com/admin/oauth-setup`
2. 点击 "开始 OAuth 认证" 按钮
3. 完成 Raindrop.io 授权流程
4. 系统会自动存储 tokens

## 验证部署

1. 检查书签页面是否正常加载: `https://me.deeptoai.com/bookmarks`
2. 查看服务器日志确认 token 刷新正常运行
3. 测试标签过滤功能

## 故障排除

### Token 刷新失败
- 检查环境变量是否正确设置
- 验证 Raindrop.io OAuth 应用配置
- 查看服务器日志了解具体错误信息

### 存储连接问题
- **Supabase**: 验证 URL 和 key 是否正确
- **Vercel KV**: 检查 KV 数据库是否正确连接到项目
- **环境变量**: 确认加密的 token 已正确添加

### 建议的测试顺序
1. 先尝试 Supabase 方案(最稳定)
2. 如果 Vercel KV 可用,可以考虑迁移
3. 环境变量方案作为临时解决方案

## 注意事项
- 所有 tokens 都使用 AES-256 加密存储
- Refresh tokens 有效期为 180 天
- 系统会自动在 token 过期前刷新
- Cron job 每天检查一次 token 状态
Loading
Loading