优化登录逻辑的实现,将认证请求和token验证的处理分成两个逻辑文件。新增交叉评查任务列表的页面(尚未对接真实数据)。

This commit is contained in:
2025-07-16 14:32:20 +08:00
parent d876d66dcb
commit 328f326db3
13 changed files with 1729 additions and 131 deletions
+182
View File
@@ -0,0 +1,182 @@
# 认证模块 (Authentication Module)
这个文件夹包含了整个应用的用户认证和会话管理功能。
## 📁 文件结构
```
app/api/login/
├── README.md # 本文档
├── auth.server.ts # 🔐 认证核心实现
├── auth-exports.server.ts # 📤 认证函数导出入口
├── oauth-client.ts # 🌐 OAuth2.0 客户端
├── token-manager.server.ts # 🎫 Token 管理器
└── OAuth2.0认证协议集成指南.md # 📖 OAuth2.0 集成文档
```
## 🔧 核心文件说明
### `auth.server.ts` - 认证核心实现
包含所有认证相关的核心功能:
- **会话管理**: 基于 Cookie 的安全会话存储
- **用户认证**: 检查用户登录状态
- **Token 刷新**: 自动刷新过期的 OAuth Token
- **登录/登出**: 创建和销毁用户会话
主要函数:
- `getUserSession()` - 获取用户会话(带 Token 刷新)
- `createUserSession()` - 创建登录会话
- `logout()` - 销毁会话并登出
- `getSession()` - 获取原始会话对象
### `auth-exports.server.ts` - 导出入口
这个文件解决了 Remix + Vite 架构中的一个重要问题:
**问题**: 同构文件(.tsx)不能直接导入 .server.ts 文件
**原因**: 防止服务器端敏感代码被打包到客户端
**解决**: 通过这个 .server.ts 文件重新导出认证函数
```typescript
// ✅ 正确的导入方式
import { getUserSession } from "~/api/login/auth-exports.server";
// ❌ 错误的导入方式(会导致构建错误)
import { getUserSession } from "~/api/login/auth.server";
```
### `oauth-client.ts` - OAuth2.0 客户端
实现 OAuth2.0 认证协议的客户端功能:
- 生成授权 URL
- 获取访问令牌
- 获取用户信息
- 状态值生成和验证
### `token-manager.server.ts` - Token 管理
负责 OAuth Token 的生命周期管理:
- Token 有效期检查
- 自动刷新即将过期的 Token
- Token 错误处理
## 🚀 使用指南
### 在路由中检查用户认证
```typescript
// app/routes/some-route.tsx
import { getUserSession } from "~/api/login/auth-exports.server";
export async function loader({ request }: LoaderFunctionArgs) {
const { isAuthenticated, userRole } = await getUserSession(request);
if (!isAuthenticated) {
return redirect("/login");
}
// 检查权限
if (userRole !== 'developer') {
throw new Response("权限不足", { status: 403 });
}
return json({ userRole });
}
```
### 处理用户登出
```typescript
// app/routes/some-route.tsx
import { logout } from "~/api/login/auth-exports.server";
export async function action({ request }: ActionFunctionArgs) {
const formData = await request.formData();
if (formData.get("intent") === "logout") {
return logout(request);
}
return null;
}
```
### 创建登录会话
```typescript
// app/routes/callback.tsx
import { createUserSession } from "~/api/login/auth-exports.server";
export async function loader({ request }: LoaderFunctionArgs) {
// OAuth 认证成功后...
// 根据用户信息判断角色
const userRole = userInfo.username === "admin" ? "developer" : "common";
return createUserSession(true, userRole, "/dashboard");
}
```
## 🛡️ 安全特性
### Cookie 安全配置
```typescript
cookie: {
httpOnly: true, // 防止 XSS 攻击
sameSite: "lax", // CSRF 保护
secure: false, // 开发环境设为 false,生产环境应为 true
maxAge: 7200, // 2小时过期
}
```
### Token 自动刷新
- 检查 Token 是否即将过期(5分钟内)
- 自动使用 refresh_token 获取新的 access_token
- 刷新失败时自动登出用户
### 用户角色权限
- `common`: 普通用户,基本功能访问权限
- `developer`: 开发者/管理员,完整系统管理权限
## 🔄 OAuth2.0 登录流程
```mermaid
sequenceDiagram
participant User as 用户
participant App as 应用
participant IDaaS as IDaaS平台
User->>App: 访问受保护页面
App->>User: 重定向到 /login
User->>App: 点击"统一身份认证登录"
App->>IDaaS: 重定向到 IDaaS 登录页
User->>IDaaS: 完成登录
IDaaS->>App: 回调并返回 code
App->>IDaaS: 使用 code 获取 access_token
IDaaS->>App: 返回 access_token
App->>IDaaS: 使用 access_token 获取用户信息
IDaaS->>App: 返回用户信息
App->>App: 创建用户会话
App->>User: 重定向到目标页面
```
## 🚨 注意事项
### 开发环境配置
1. 确保 OAuth 配置正确(`app/config/api-config.ts`
2. IDaaS 平台中配置正确的回调地址
3. 检查 Cookie 的 `secure` 设置(开发环境为 `false`
### 生产环境部署
1. 使用环境变量管理敏感信息(secrets)
2. 启用 HTTPS 并设置 `secure: true`
3. 配置正确的域名和回调地址
4. 监控 Token 刷新日志
### 调试技巧
- 查看浏览器 Application 标签页中的 Cookies
- 检查服务器控制台的认证相关日志
- 使用 Remix Dev Tools 查看 loader 数据
## 📖 相关文档
- [OAuth2.0认证协议集成指南](./OAuth2.0认证协议集成指南.md)
- [Remix Session Storage 文档](https://remix.run/docs/en/main/utils/sessions)
- [Cookie Security Best Practices](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies)