Penny Lens 服务端认证系统详解

2025年1月27日
6 分钟阅读
作者:Penny Lens Team

认证系统文档

1. 认证系统概述

Penny Lens Serverless 项目采用统一的认证系统,支持多平台登录(支付宝、微信等)以及邮箱/密码登录方式。本系统基于 JWT (JSON Web Token) 实现用户身份验证,并提供完善的会话管理机制。

2. 核心功能

  • 统一登录接口: 支持多平台身份验证的统一入口
  • JWT Token 认证: 基于 JWT 的安全认证机制
  • 会话管理: 支持多设备登录、会话刷新和注销
  • 密码加密: 采用 bcrypt 算法对用户密码进行加密存储
  • 第三方平台集成: 支持支付宝、微信等平台的 OAuth 认证
  • 权限验证: 细粒度的用户权限验证机制

3. 数据模型

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
}

3.2 会话模型 (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.3 登录记录模型 (UserLoginRecord)

interface UserLoginRecord {
  _id?: string;           // 记录ID
  userId: string;         // 用户ID
  loginTime: number;      // 登录时间
  platform: LoginPlatform; // 登录平台
  deviceId?: string;      // 设备ID
  deviceInfo?: string;    // 设备信息
  ipAddress?: string;     // IP地址
  success: boolean;       // 登录是否成功
  errorMessage?: string;  // 失败原因
}

4. 统一登录服务

4.1 UnifiedLoginService 概述

UnifiedLoginService 是认证系统的核心服务,提供统一的登录入口和会话管理功能。该服务负责处理不同登录方式的身份验证逻辑,并生成统一的 JWT Token 返回给客户端。

4.2 主要方法

class UnifiedLoginService extends BaseService {
  /**
   * 统一登录方法
   * @param params 登录参数
   * @returns 登录结果,包含用户信息和Token
   */
  public async login(params: UnifiedLoginRequest): Promise<UserResponse> {}
  
  /**
   * 验证JWT Token
   * @param token JWT Token字符串
   * @returns 验证结果,包含用户信息
   */
  public async verifyToken(token: string): Promise<VerifyTokenResult> {}
  
  /**
   * 刷新会话Token
   * @param token 当前Token
   * @returns 新的Token
   */
  public async refreshToken(token: string): Promise<string> {}
  
  /**
   * 注销登录
   * @param token 当前Token
   */
  public async logout(token: string): Promise<void> {}
}

5. 登录流程详解

5.1 统一登录流程

  1. 请求处理: 客户端发送包含登录信息的请求到 /api 接口,指定 action: "user.login"
  2. 路由分发: router.ts 根据 action 找到对应的 UserController.login 方法
  3. 参数验证: UserController 验证请求参数的合法性
  4. 登录处理: 调用 UnifiedLoginService.login 处理登录逻辑
  5. 平台认证: 根据 platform 字段调用相应的第三方认证方法(如微信或支付宝)
  6. 用户匹配: 查找或创建对应的用户记录
  7. 会话创建: 生成 JWT Token,创建新的会话记录
  8. 响应返回: 返回包含用户信息和 Token 的响应

5.2 Token 验证流程

  1. 请求拦截: 对于需要认证的路由,router.ts 会拦截请求并提取 Token
  2. Token 解析: 使用 jsonwebtoken 库解析 Token
  3. Token 验证: 验证 Token 的有效性,包括签名和过期时间
  4. 会话验证: 验证 Token 对应的会话是否有效
  5. 用户验证: 验证用户状态是否正常
  6. 权限检查: 检查用户是否有权限访问请求的资源
  7. 请求放行: 验证通过后,将用户信息附加到请求中并放行

6. 登录方式详解

6.1 邮箱/密码登录

请求参数:

interface UserLoginRequest {
  email: string;         // 用户邮箱
  password: string;      // 用户密码
  platform: "email";     // 登录平台
  deviceId?: string;     // 设备ID
  deviceInfo?: string;   // 设备信息
}

处理流程:

  1. 根据邮箱查询用户
  2. 验证密码是否匹配(使用 bcrypt 比较)
  3. 生成登录凭证

6.2 微信登录

请求参数:

interface WechatLoginRequest {
  code: string;          // 微信授权码
  platform: "wechat";    // 登录平台
  deviceId?: string;     // 设备ID
  deviceInfo?: string;   // 设备信息
}

处理流程:

  1. 使用微信授权码调用微信 API 获取 openId
  2. 根据 openId 查询或创建用户
  3. 生成登录凭证

6.3 支付宝登录

请求参数:

interface AlipayLoginRequest {
  authCode: string;      // 支付宝授权码
  platform: "alipay";    // 登录平台
  deviceId?: string;     // 设备ID
  deviceInfo?: string;   // 设备信息
}

处理流程:

  1. 使用支付宝授权码调用支付宝 API 获取 userId
  2. 根据 userId 查询或创建用户
  3. 生成登录凭证

7. 会话管理

7.1 Token 生成

JWT Token 使用项目配置中的 jwtSecret 进行签名,有效期默认为 7 天(可通过 jwtExpiresIn 配置)。Token 包含以下信息:

  • iss: 签发者
  • sub: 主题(用户ID)
  • exp: 过期时间
  • iat: 签发时间
  • jti: JWT ID(会话唯一标识)

7.2 会话控制

  • 多设备登录: 支持同一账号在多个设备上登录
  • 会话上限: 可配置单个账号的最大会话数
  • 会话踢出: 支持强制下线指定会话
  • 会话状态: 会话可处于活跃、已过期、已销毁等状态

7.3 Token 刷新机制

当 Token 即将过期时,客户端可以使用当前有效的 Token 请求刷新,获取新的 Token 而无需重新登录。刷新 Token 的条件:

  • 当前 Token 仍在有效期内
  • Token 对应的会话仍处于活跃状态
  • 用户状态正常

8. 安全机制

8.1 密码安全

  • 密码加密: 使用 bcrypt 算法对用户密码进行加密存储,不可逆
  • 密码策略: 建议实施密码复杂度要求(长度、字符组合等)
  • 密码历史: 可选实现密码历史记录,避免重复使用旧密码
  • 敏感操作验证: 重要操作需要重新验证密码

8.2 Token 安全

  • HTTPS 传输: 所有含 Token 的请求必须通过 HTTPS 协议传输
  • Token 存储: 客户端应使用安全的方式存储 Token,避免 XSS 攻击
  • Token 验证: 服务端每次请求都验证 Token 的有效性
  • Token 泄露处理: 支持主动失效特定 Token

8.3 安全防护

  • 输入验证: 所有用户输入都进行严格的验证和过滤
  • 请求频率限制: 对登录等敏感操作实施请求频率限制,防止暴力破解
  • 异常日志: 记录登录失败、异常访问等安全相关事件
  • IP 异常检测: 检测并处理异常 IP 访问

9. API 接口说明

9.1 统一登录接口

请求:

{
  "action": "user.login",
  "params": {
    "platform": "email", // 或 "wechat", "alipay"
    "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": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "createdAt": 1639149835278,
    "updatedAt": 1642345678901
  }
}

9.2 Token 验证接口

请求:

{
  "action": "user.verifyToken",
  "params": {
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
  }
}

响应:

{
  "code": 200,
  "message": "验证成功",
  "data": {
    "valid": true,
    "userId": "61c0c50b6d1b2c001fd2a345",
    "username": "user123",
    "expiresAt": 1644923456789
  }
}

9.3 注销登录接口

请求:

{
  "action": "user.logout",
  "params": {}
}

响应:

{
  "code": 200,
  "message": "注销成功",
  "data": null
}

10. 错误处理

10.1 常见错误类型

  • 认证失败: 用户名或密码错误,Token 无效或已过期
  • 权限不足: 用户尝试访问无权限的资源
  • 会话异常: 会话已被销毁、用户已被禁用
  • 请求频率过高: 短时间内登录尝试次数过多
  • 参数验证失败: 输入参数格式不正确或缺失

10.2 错误码与消息

错误码错误类型错误消息处理建议
400ValidationException参数验证失败检查输入参数是否正确
401UnauthorizedException未授权访问请先登录获取有效Token
403ForbiddenException权限不足检查用户权限
404NotFoundException用户不存在确认用户是否已注册
500DatabaseException数据库操作失败稍后重试或联系管理员

11. 开发与集成指南

11.1 前端集成

  • 登录请求: 调用统一登录接口,传入正确的平台和凭证信息
  • Token 存储: 使用安全的方式存储返回的 Token(如 localStorage + HTTP Only Cookie)
  • 请求拦截: 为所有需要认证的请求添加 Token 头
  • Token 刷新: 实现 Token 自动刷新机制,避免用户频繁登录
  • 注销处理: 实现注销功能,清除存储的 Token

11.2 后端集成

  • 路由配置: 在 routes.ts 中正确设置 requireAuth 属性
  • 权限验证: 使用 validateUserAccess 方法验证用户权限
  • 异常处理: 使用 wrapAsync 包装异步方法,统一处理异常
  • 会话管理: 合理使用会话管理相关的服务方法

12. 最佳实践

  • 安全性优先: 始终将安全性放在首位,遵循最小权限原则
  • Token 保护: 客户端应妥善保护 Token,避免泄露
  • 定期更新: 建议用户定期更改密码,特别是涉及敏感操作的用户
  • 多重验证: 对于关键操作,建议实现多重验证机制
  • 异常监控: 建立完善的异常日志和监控机制,及时发现和处理安全问题
  • 性能优化: 优化认证和会话查询性能,减少数据库压力

13. 未来优化方向

  • 支持更多登录方式: 如手机号验证码登录、第三方社交账号登录等
  • 双因素认证: 增加短信、邮箱验证码等双因素认证机制
  • 单点登录: 实现多应用间的单点登录功能
  • 会话管理可视化: 提供用户会话管理的可视化界面
  • 自适应认证: 根据风险评估动态调整认证强度