cursor-init/docs/jwt-usage-examples.md
expressgy a23d336ebd refactor: 重构项目架构并标准化开发规范
- 重构项目结构:controllers/services -> modules模块化组织

- 新增Drizzle ORM集成和数据库schema定义

- 添加完整的开发规范文档(.cursor/rules/)

- 重新组织插件结构为子目录方式

- 新增用户模块和示例代码

- 更新类型定义并移除试验性代码

- 添加API文档和JWT使用示例

关联任务计划文档
2025-06-30 01:25:17 +08:00

214 lines
6.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# JWT 用户类型使用指南
## 概述
我们定义了完整的JWT类型系统提供类型安全的JWT操作。
## 类型定义
### 1. JwtUserType - JWT中的用户信息
```typescript
interface JwtUserType {
userId: number;
username: string;
email: string;
nickname?: string;
status: number;
role?: string;
}
```
### 2. JwtPayloadType - 完整的JWT载荷
```typescript
interface JwtPayloadType extends JwtUserType {
iat: number; // 发行时间
exp: number; // 过期时间
sub?: string; // 主题
iss?: string; // 发行者
aud?: string; // 受众
jti?: string; // JWT ID
nbf?: number; // 生效时间
}
```
## 使用示例
### 1. 在认证Controller中生成JWT Token
```typescript
// auth.controller.ts
import { createJwtPayload } from '@/utils/jwt.helper';
import type { UserInfoType } from '@/modules/sample/example.schema';
export const authController = new Elysia()
.use(jwtPlugin)
.post('/login', async ({ body, jwt }) => {
// 用户登录验证逻辑...
const userInfo: UserInfoType = await getUserFromDatabase(body.username);
// 创建JWT载荷
const payload = createJwtPayload(userInfo, {
role: 'user', // 可选的角色信息
issuer: 'my-api',
audience: 'web-app',
});
// 生成Token
const token = await jwt.sign(payload);
return {
code: 0,
message: '登录成功',
data: {
token,
user: payload, // 返回用户信息(不含敏感数据)
},
};
});
```
### 2. 在需要认证的Controller中使用用户信息
```typescript
// user.controller.ts
import { formatUserForLog, isValidJwtUser } from '@/utils/jwt.helper';
import type { JwtUserType } from '@/type/jwt.type';
export const userController = new Elysia()
.use(jwtAuthPlugin)
.get('/profile', async ({ user, payload }) => {
// user 自动推断为 JwtUserType 类型
// payload 自动推断为 JwtPayloadType 类型
// 验证用户有效性
if (!isValidJwtUser(payload)) {
Logger.warn(`无效用户尝试访问: ${formatUserForLog(user)}`);
return { code: 401, message: '用户状态异常', data: null };
}
// 使用类型安全的用户信息
Logger.info(`用户查看个人资料: ${formatUserForLog(user)}`);
// 获取完整的用户信息(从数据库)
const fullUserInfo = await getUserById(user.userId);
return {
code: 0,
message: '获取成功',
data: fullUserInfo,
};
});
```
### 3. 在Service中使用JWT用户类型
```typescript
// user.service.ts
import type { JwtUserType } from '@/type/jwt.type';
export class UserService {
// 使用JWT用户类型作为参数
async updateUserProfile(currentUser: JwtUserType, updateData: any) {
// 检查权限
if (currentUser.status !== 1) {
throw new Error('用户状态异常,无法操作');
}
// 更新用户信息
const updatedUser = await db.update(users)
.set(updateData)
.where(eq(users.id, currentUser.userId));
Logger.info(`用户资料更新: ${currentUser.username} (ID: ${currentUser.userId})`);
return updatedUser;
}
// 根据JWT用户信息获取权限
async getUserPermissions(jwtUser: JwtUserType): Promise<string[]> {
const permissions = await db.select()
.from(userPermissions)
.where(eq(userPermissions.userId, jwtUser.userId));
return permissions.map(p => p.permission);
}
}
```
### 4. Token状态检查
```typescript
// middleware/token-check.ts
import {
isTokenExpiringSoon,
getTokenRemainingTime,
formatRemainingTime
} from '@/utils/jwt.helper';
export const tokenStatusMiddleware = (app: Elysia) =>
app.derive(({ payload, user }) => {
if (!payload) return {};
// 检查Token是否即将过期
const expiringSoon = isTokenExpiringSoon(payload, 30); // 30分钟阈值
const remainingTime = getTokenRemainingTime(payload);
if (expiringSoon) {
Logger.warn(`用户Token即将过期: ${user.username}, 剩余时间: ${formatRemainingTime(remainingTime)}`);
}
return {
tokenInfo: {
expiringSoon,
remainingTime,
formattedTime: formatRemainingTime(remainingTime),
},
};
});
```
### 5. 角色权限检查
```typescript
// middleware/role-check.ts
import type { JwtUserType } from '@/type/jwt.type';
export function requireRole(requiredRole: string) {
return (app: Elysia) =>
app.onBeforeHandle(({ user, set }) => {
const jwtUser = user as JwtUserType;
if (!jwtUser.role || jwtUser.role !== requiredRole) {
Logger.warn(`权限不足: 用户${jwtUser.username}尝试访问需要${requiredRole}角色的资源`);
set.status = 403;
return {
code: 403,
message: '权限不足',
data: null,
};
}
});
}
// 使用示例
export const adminController = new Elysia()
.use(jwtAuthPlugin)
.use(requireRole('admin'))
.get('/admin-only', () => {
return { message: '只有管理员能看到这个内容' };
});
```
## 🎯 类型安全的好处
1. **编译时检查**: TypeScript 会在编译时检查所有JWT相关操作
2. **智能提示**: IDE 提供完整的属性提示和自动补全
3. **重构安全**: 修改用户类型时,所有相关代码都会得到类型检查
4. **文档作用**: 类型定义本身就是最好的文档
## 📝 最佳实践
1. **总是使用类型注解**: 在Service方法中明确使用 `JwtUserType` 类型
2. **验证用户状态**: 使用 `isValidJwtUser()` 检查用户有效性
3. **记录操作日志**: 使用 `formatUserForLog()` 格式化用户信息
4. **检查Token状态**: 在关键操作前检查Token是否即将过期
5. **权限分离**: 使用角色字段实现细粒度权限控制