集合:登录会话(sessions)
字数
1317 字
阅读时间
6 分钟
1. 目的与使用场景
- 存储 MindGuard 用户的登录会话信息,支持多设备管理、刷新 token、风控追踪。
- 主要由
authLogin、/api/auth/refresh、/api/auth/logout云函数/接口读写;前端services/auth.js在鉴权时依赖该集合确认会话有效性。
2. Schema 定义
| 字段 | 类型 | 必填 | 默认值 | 约束/校验 | 说明 | 索引 | 权限 |
|---|---|---|---|---|---|---|---|
| _id | string | 是 | - | TCB 自动生成 | 会话主键 | PK | P1 |
| user_id | string | 是 | - | 指向 users._id | 用户指针 | IDX | P2 |
| openid | string | 是 | - | 长度 ≤ 64 | 微信 openid | UK | P2 |
| session_token | string | 是 | - | 长度 32-128 | 前端携带的访问 token | UK | P0 |
| refresh_token | string | 是 | - | 长度 32-128 | 用于刷新 | - | P0 |
| device_fingerprint | string | 否 | - | hash 字符串 | 设备指纹,用于风控 | IDX | P1 |
| platform | string | 是 | miniapp | 枚举:miniapp/ios/android/web | 来源端 | IDX | P2 |
| ip_region | object | 否 | - | {country, province, city} | 最近一次登录来源 | - | P2 |
| login_channel | string | 是 | 枚举:wechat/student_bind/guardian_invite | 登录渠道 | IDX | P2 | |
| status | string | 是 | active | 枚举:active/expired/revoked/blocked | 会话状态 | IDX | P1 |
| expires_at | date | 是 | - | 必须大于 createdAt | 访问 token 过期时间 | TTL | P0 |
| refresh_expires_at | date | 是 | - | 必须大于 expires_at | refresh token 过期时间 | IDX | P0 |
| last_refresh_at | date | 否 | - | - | 最近刷新时间 | - | P1 |
| last_active_at | date | 否 | - | - | 最近一次鉴权成功时间 | IDX | P1 |
| failed_attempts | number | 否 | 0 | ≥0 | 连续失败刷新次数 | - | P2 |
| meta | object | 否 | {} | 键值对 | 设备信息(系统版本、App 版本) | - | P2 |
| createdAt | date | 是 | - | 服务端时间 | 创建时间 | IDX | P1 |
| updatedAt | date | 是 | - | 服务端时间 | 更新时间 | IDX | P1 |
| createdBy | string | 否 | system | - | 创建来源 | - | P2 |
| updatedBy | string | 否 | system | - | 更新来源 | - | P2 |
状态枚举:
active:会话可用。expired:expires_at已过期,等待 refresh 或清理。revoked:用户主动退出或后台手动吊销。blocked:风控标记设备风险,阻止继续使用。
3. 索引设计
session_token_1:唯一索引,快速验证 token。结合status='active'查询。user_id_1_status_1:多设备管理,支持查询某用户的所有会话。device_fingerprint_1_status_1:风控策略,用于识别异常设备。expires_at_1:TTL 索引(自动清理过期会话),生效时间 =expires_at。refresh_expires_at_1:辅助索引,用于批量失效即将过期的 refresh token。
4. 访问控制(TCB 权限)
json
{
"read": "openid == auth.openid || auth.role in ['ops','counselor']",
"write": "openid == auth.openid || auth.role in ['ops']"
}- 普通用户仅能访问自己的会话。
- 运营(ops)可在风险排查时吊销会话,辅导员仅用于查看风险登录记录(需与合规确认)。
5. 关系与级联
- 与
users一对多关系(一个用户可有多会话)。 events集合中session_id字段引用本集合_id,用于埋点追踪。- 会话被设置为
revoked/blocked时,前端需清除本地 token 并引导重新登录。
6. 数据生命周期与合规
- TTL 自动清理
expires_at过期记录;refresh_expires_at到期的记录由定时任务标记为expired。 - 记录设备与 IP 信息仅用于安全审计,不对普通用户展示。
- 登录协议勾选版本在
users.consent_version中维护,不在本集合存储。
7. API/云函数契约映射
| 接口/函数 | 读/写 | 使用字段 | 过滤条件 | 说明 |
|---|---|---|---|---|
authLogin | 写 | session_token, refresh_token, expires_at, refresh_expires_at, device_fingerprint, status | - | 登录成功时创建会话 |
/api/auth/refresh | 读/写 | refresh_token, status, expires_at, last_refresh_at | status='active' 且 refresh_expires_at>now() | 刷新会话 |
/api/auth/logout | 写 | status | _id=session_id | 将状态改为 revoked |
ensureLoggedIn | 读 | session_token, status, expires_at | session_token=header | 前端鉴权校验 |
风控定时任务 riskMonitor | 写 | status | failed_attempts>=5 | 将异常会话置为 blocked |
8. 示例文档
json
{
"_id": "sess_20240407_001",
"user_id": "usr_001",
"openid": "oAbcd123",
"session_token": "st_5fe9d1b4d2f24f3a9f34d4f1caa9b701",
"refresh_token": "rt_22a7334a807347c7bfc3dd04b6d9db16",
"device_fingerprint": "dfg_wechat_ios_13_123456",
"platform": "miniapp",
"ip_region": {"country": "CN", "province": "北京", "city": "海淀"},
"login_channel": "wechat",
"status": "active",
"expires_at": "2024-04-14T10:20:00Z",
"refresh_expires_at": "2024-05-07T10:20:00Z",
"last_refresh_at": "2024-04-09T11:00:00Z",
"last_active_at": "2024-04-09T11:05:00Z",
"failed_attempts": 0,
"meta": {"os": "iOS", "os_version": "16.4", "app_version": "1.3.0"},
"createdAt": "2024-04-07T10:20:00Z",
"updatedAt": "2024-04-09T11:05:00Z"
}9. 常用查询样例
javascript
// 校验前端传入的 session_token
const session = await db.collection('sessions').where({ session_token: token, status: 'active' }).get();
// 查找用户所有活跃会话,支持设备管理
const activeSessions = await db.collection('sessions').where({ user_id: userId, status: 'active' }).get();
// 风控:筛选异常失败次数的设备
const risky = await db.collection('sessions').where({ device_fingerprint: df, failed_attempts: db.command.gte(3) }).get();10. 边界与错误码
E_SESSION_NOT_FOUND:传入的session_token不存在或已过期。E_SESSION_REVOKED:会话被手动吊销,需重新登录。E_REFRESH_EXPIRED:refresh token 失效,不允许继续刷新。- 并发刷新:使用事务或
updatedAt检查避免重复颁发 token。
11. 变更影响评估
- 修改字段需同步更新
authLogin、/api/auth/refresh返回值及前端存储逻辑。 - TTL 调整会影响会话保留时长,需提前通知运营与测试。
- 新增风控字段应同步更新埋点或日志上报策略。
12. 假设与待确认
device_fingerprint由前端基于设备信息+小程序版本哈希生成,需确认一致性算法。ip_region数据来源于云函数解析,需确认是否符合学校网络合规要求。