Penny Lens 认证系统完整文档
2026年6月25日 · 5 分钟阅读 · ixNieStudio
整合前端认证与服务端认证的完整文档,涵盖多平台登录、JWT 会话管理、QR 码跨设备登录、安全机制等核心功能。
认证系统完整文档
最后更新:2026-06-25
版本:v1.0
范围:前端认证 + 服务端认证 + 安全机制
一、系统概述
Penny Lens 认证系统采用前后端分离架构,支持多平台登录(微信、支付宝、邮箱/密码)、QR 码跨设备登录、JWT Token 会话管理等核心功能。
核心能力
| 能力 | 描述 |
|---|---|
| 多平台登录 | 微信、支付宝、邮箱/密码 |
| QR 码登录 | 手机扫码登录 PC 端 |
| JWT 会话 | Token 生成、验证、刷新、失效 |
| 安全机制 | bcrypt 密码加密、请求频率限制、IP 异常检测 |
二、前端认证模块
2.1 模块架构
src/├── pages/auth/ # 认证页面│ ├── index.vue # 身份令牌页面│ └── qr-login.vue # 二维码登录页面├── pages/mine/login.vue # 登录/注册页面├── store/user.ts # 用户状态管理├── services/api/user.ts # 用户API服务├── services/api/auth.ts # 认证API服务├── utils/auth.ts # 认证工具函数├── utils/uniapi/auth.ts # UniApp认证API├── utils/uniapi/platformLogin.ts # 平台登录工具├── types/user.ts # 用户类型定义├── types/auth.ts # 认证类型定义└── router/guard.ts # 路由守卫2.2 登录方式
邮箱/密码登录
流程:用户输入 → 前端验证 → 发送请求 → 后端验证 → 返回 JWT → 保存 Token
核心接口:
interface LoginRequest { username: string; // 用户名或邮箱 password: string; // 密码 deviceId: string; // 设备ID deviceInfo: string; // 设备信息}
interface LoginResponse { token: string; // JWT令牌 userInfo: UserInfo; // 用户信息 expiresIn: number; // 过期时间(秒)}微信登录
流程:调用微信授权 API → 获取授权码 → 发送到后端 → 获取用户信息 → 返回 JWT
async function wechatLogin(): Promise<LoginResponse> { const authResult = await uni.login({ provider: 'weixin' }) if (authResult[1].code) { const response = await authApi.wechatLogin({ code: authResult[1].code, deviceId: getDeviceId(), deviceInfo: getDeviceInfo() }) if (response.code === 200) { setToken(response.data.token) setUserInfo(response.data.userInfo) return response.data } } throw new Error('微信登录失败')}支付宝登录
流程与微信登录类似:调用 uni.login({ provider: 'alipay' }) 获取 authCode,发送到后端换取用户信息并返回 JWT 令牌。
2.3 QR 码跨设备登录
功能:允许用户通过手机小程序扫码在 PC 端完成登录,支持微信和支付宝两个平台。
登录流程:
PC端(被扫端) 服务端 手机端(扫码端) | | | |-- 1. 生成二维码 ---------->| | |<-- 2. 返回二维码URL ------| | | | | | |<-- 3. 扫码确认 ----------| | |-- 4. 返回确认结果 ------->| | | | |-- 5. 轮询登录状态 ------->| | |<-- 6. 返回登录结果 -------| |轮询状态说明:
| 状态 | 说明 | 下一步操作 |
|---|---|---|
pending | 等待扫码 | PC端继续轮询 |
scanned | 已扫码,等待确认 | PC端继续轮询 |
confirmed | 已确认,登录成功 | PC端停止轮询,使用返回的token |
expired | 会话已过期 | PC端重新生成二维码 |
cancelled | 会话已取消 | PC端重新生成二维码 |
实现要点:
- PC 端:调用
user.generateQrCodeLogin生成会话,每 2 秒轮询user.pollQrCodeLogin - 小程序端:使用
wx.scanCode()(微信)或my.scan()(支付宝)扫描二维码 - 二维码默认 5 分钟过期
三、服务端认证系统
3.1 数据模型
用户模型 (User)
interface User { _id?: string; // 用户唯一标识 username: string; // 用户名 password: string; // 加密后的密码 email?: string; // 邮箱 avatar?: string; // 头像 URL phoneNumber?: string; // 电话号码 userType: UserType; // 用户类型 status: UserStatus; // 用户状态 createdAt: number; // 创建时间戳 updatedAt: number; // 更新时间戳 delFlag: boolean; // 软删除标记 lastLoginAt?: number; // 最后登录时间 currentSessionId?: string; // 当前会话ID}会话模型 (Session)
interface Session { _id?: string; // 会话ID userId: string; // 关联的用户ID token: string; // JWT Token deviceId?: string; // 设备唯一标识 deviceInfo?: string; // 设备信息 ipAddress?: string; // IP地址 loginTime: number; // 登录时间 expireTime: number; // 过期时间 status: SessionStatus; // 会话状态 platform?: LoginPlatform; // 登录平台}3.2 统一登录服务
UnifiedLoginService 是认证系统的核心服务,提供统一的登录入口和会话管理功能。
class UnifiedLoginService extends BaseService { public async login(params: UnifiedLoginRequest): Promise<UserResponse> {} public async verifyToken(token: string): Promise<VerifyTokenResult> {} public async refreshToken(token: string): Promise<string> {} public async logout(token: string): Promise<void> {}}3.3 登录流程
- 请求处理:客户端发送请求到
/api,指定action: "user.login" - 路由分发:
router.ts根据 action 找到对应的UserController.login方法 - 参数验证:验证请求参数的合法性
- 登录处理:调用
UnifiedLoginService.login处理登录逻辑 - 平台认证:根据
platform字段调用相应的第三方认证方法 - 用户匹配:查找或创建对应的用户记录
- 会话创建:生成 JWT Token,创建新的会话记录
- 响应返回:返回包含用户信息和 Token 的响应
3.4 Token 验证流程
- 请求拦截:对于需要认证的路由,提取 Token
- Token 解析:使用
jsonwebtoken库解析 Token - Token 验证:验证签名和过期时间
- 会话验证:验证 Token 对应的会话是否有效
- 用户验证:验证用户状态是否正常
- 权限检查:检查用户是否有权限访问请求的资源
四、安全机制
4.1 密码安全
- 密码加密:使用 bcrypt 算法对用户密码进行加密存储,不可逆
- 密码策略:建议实施密码复杂度要求(长度、字符组合等)
- 密码历史:可选实现密码历史记录,避免重复使用旧密码
- 敏感操作验证:重要操作需要重新验证密码
4.2 Token 安全
- HTTPS 传输:所有含 Token 的请求必须通过 HTTPS 协议传输
- Token 存储:客户端应使用安全的方式存储 Token,避免 XSS 攻击
- Token 验证:服务端每次请求都验证 Token 的有效性
- Token 泄露处理:支持主动失效特定 Token
4.3 安全防护
- 输入验证:所有用户输入都进行严格的验证和过滤
- 请求频率限制:对登录等敏感操作实施请求频率限制,防止暴力破解
- 异常日志:记录登录失败、异常访问等安全相关事件
- IP 异常检测:检测并处理异常 IP 访问
4.4 会话控制
- 多设备登录:支持同一账号在多个设备上登录
- 会话上限:可配置单个账号的最大会话数
- 会话踢出:支持强制下线指定会话
- 会话状态:会话可处于活跃、已过期、已销毁等状态
4.5 Token 刷新机制
当 Token 即将过期时,客户端可以使用当前有效的 Token 请求刷新,获取新的 Token 而无需重新登录。
刷新条件:
- 当前 Token 仍在有效期内
- Token 对应的会话仍处于活跃状态
- 用户状态正常
五、API 接口
5.1 统一登录接口
请求:
{ "action": "user.login", "params": { "platform": "email", "email": "user@example.com", "password": "password123", "deviceId": "device123", "deviceInfo": "iOS 15.0, iPhone 13" }}响应:
{ "code": 200, "message": "登录成功", "data": { "id": "61c0c50b6d1b2c001fd2a345", "username": "user123", "email": "user@example.com", "avatar": "https://example.com/avatar.jpg", "token": "eyJhbG...VCJ9...", "createdAt": 1639149835278, "updatedAt": 1642345678901 }}5.2 Token 验证接口
请求:
{ "action": "user.verifyToken", "params": { "token": "eyJhbG...VCJ9..." }}5.3 注销登录接口
请求:
{ "action": "user.logout", "params": {}}六、错误处理
常见错误类型
| 错误码 | 错误类型 | 错误消息 | 处理建议 |
|---|---|---|---|
| 400 | ValidationException | 参数验证失败 | 检查输入参数是否正确 |
| 401 | UnauthorizedException | 未授权访问 | 请先登录获取有效Token |
| 403 | ForbiddenException | 权限不足 | 检查用户权限 |
| 404 | NotFoundException | 用户不存在 | 确认用户是否已注册 |
| 500 | DatabaseException | 数据库操作失败 | 稍后重试或联系管理员 |
七、前端集成指南
Token 管理
export const tokenUtils = { setToken(token: string): void { uni.setStorageSync('token', token) }, getToken(): string | null { return uni.getStorageSync('token') || null }, removeToken(): void { uni.removeStorageSync('token') }, isTokenExpired(token: string): boolean { try { const payload = JSON.parse(atob(token.split('.')[1])) return Date.now() >= payload.exp * 1000 } catch { return true } }}路由守卫
export const authGuard = { checkAuth(): boolean { return sessionManager.isSessionValid() }, requireAuth(path: string): boolean { const authRequiredPaths = [ '/pages/mine/profile-settings', '/pages/mine/account-settings', '/pages/mine/user-sessions', '/pages/auth/index' ] return authRequiredPaths.includes(path) }, beforeRouteEnter(to: any, from: any, next: any): void { if (authGuard.requireAuth(to.path)) { if (authGuard.checkAuth()) { next() } else { uni.navigateTo({ url: '/pages/mine/login?redirect=' + encodeURIComponent(to.path) }) } } else { next() } }}本文档整合了前端认证模块和服务端认证系统的完整内容。