6.5 KiB
6.5 KiB
JWT 用户类型使用指南
概述
我们定义了完整的JWT类型系统,提供类型安全的JWT操作。
类型定义
1. JwtUserType - JWT中的用户信息
interface JwtUserType {
userId: number;
username: string;
email: string;
nickname?: string;
status: number;
role?: string;
}
2. JwtPayloadType - 完整的JWT载荷
interface JwtPayloadType extends JwtUserType {
iat: number; // 发行时间
exp: number; // 过期时间
sub?: string; // 主题
iss?: string; // 发行者
aud?: string; // 受众
jti?: string; // JWT ID
nbf?: number; // 生效时间
}
使用示例
1. 在认证Controller中生成JWT Token
// auth.controller.ts
import { createJwtPayload } from '@/utils/jwt.helper';
import type { UserInfoType } from '@/modules/example/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中使用用户信息
// 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用户类型
// 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状态检查
// 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. 角色权限检查
// 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: '只有管理员能看到这个内容' };
});
🎯 类型安全的好处
- 编译时检查: TypeScript 会在编译时检查所有JWT相关操作
- 智能提示: IDE 提供完整的属性提示和自动补全
- 重构安全: 修改用户类型时,所有相关代码都会得到类型检查
- 文档作用: 类型定义本身就是最好的文档
📝 最佳实践
- 总是使用类型注解: 在Service方法中明确使用
JwtUserType
类型 - 验证用户状态: 使用
isValidJwtUser()
检查用户有效性 - 记录操作日志: 使用
formatUserForLog()
格式化用户信息 - 检查Token状态: 在关键操作前检查Token是否即将过期
- 权限分离: 使用角色字段实现细粒度权限控制