交易会话:二次登录、保活与被踢

项目 trade-app

  • 交易
  • 登录
  • 会话
  • 二次认证
  • 心跳
  • 单点登录

1. 背景与问题

用户打开这款 App,先登录的是 App 账户:拿到用户凭证,可以看行情、资讯、开户进度。要下单、看持仓和资金,还要再登录一次交易账户:输入交易密码(或用面容 / 指纹取出交易密码),由交易网关去对应的柜台校验。期货和证券是两套柜台,各有一个交易账户、一个交易会话。

这第二次登录带来四类问题:

  1. 应答复杂:两套柜台的登录应答各不相同,有二次认证(短信、邮箱)、强制改密、建议改密、请求过于频繁、密码过期、客户状态不允许登录等十几种分支。
  2. 静默登录:开启生物识别时,客户端会拿交易密码在后台登录一次做绑定;这次登录的应答不能弹任何界面。
  3. 保活:交易会话需要客户端定期告诉网关「还在」。
  4. 单设备在线:同一个交易账户只允许一台设备在线。被挤下线时,要让用户知道,但不能把用户踢出 App。

客户端这一侧由几块组成:交易登录管理器的主体、交易密码登录弹窗、期货与证券的二次认证页,外加一层对系统生物识别的封装。


2. 两级会话

交易账户App 账户
用户凭证 + 续期凭证HTTP 请求交易长连接鉴权期货会话号证券会话号交易网关期货柜台证券柜台
维度 App 账户 交易账户
凭证 用户凭证,有过期时间,可续期 期货、证券各一个会话号
怎么来 认证中心登录 交易网关登录应答
本地有过期时间吗 有,提前续期 没有,由网关告知是否失效
保活 续期 每 10 秒一次账户心跳
失效时 续期凭证失效才登出 App 只下线交易会话,App 仍在登录态

交易长连接本身用的是 App 账户的凭证;交易会话是这条连接上的第二层。两层分开处理,是整个设计的出发点。


3. 整体设计:应答驱动

交易长连接收到期货或证券的应答后,不在连接层判断业务,而是把整个信封赋给交易登录管理器上对应的属性:证券登录载体、期货登录载体、重复登录载体、断线载体、登出载体、改密与重置密码载体。每个属性的观察器就是一个处理器。

赋值
交易登录管理登录防重入标记当前登录账号与类型生物识别绑定中的请求序号交易首页生物识别登录的请求序号期货心跳定时器证券心跳定时器强制改密 / 建议改密标记login(账号类型, 是否尝试生物识别, 成功回调, 失败回调)证券载体登录重复登录主推登出重置密码 / 改密期货载体登录账户断线主推二次认证验证码交易连接按类型赋值载体

一个交易会话的生命周期:

密码或生物识别需要短信 / 邮箱验证验证通过强制改密改密后重新登录成功且会话号非 0密码错误 / 过期 / 状态不允 许每 10 秒账户心跳被挤下线 / 会话校验失败用户确认后重新登录主动登出
未登录登录中二次认证已登录改密掉线

4. 关键实现

4.1 一个入口

交易登录最早散在登录弹窗里,各个页面各自调用。后来重写了交易登录,收成登录管理器上的一个入口,把各个页面上原来的登录调用都换成这个入口,旧版本的登录管理随之删除。

入口做的第一件事是防重入:1 秒内重复调用直接返回。然后按账号类型读出本地的交易账号,读不到就不登录;再根据生物识别的绑定状态决定走哪条路。

是否否是否是是否识别成功改用密码
login(账号类型)1 秒内已经调过?直接返回读到交易账号?生物识别已绑定且可用?交易密码弹窗系统指纹 / 面容变更过?解绑并提示已失效弹出方式选择,同时发起识 别取出交易密码,带新请求序 号发登录

登录方式选择视图,以及面容 / 指纹登录的判断流程也在这里。生物识别的细节不在这里展开,这里只关心它对会话的影响:它也是一次普通的交易登录,只是密码来自本地。

4.2 两套柜台的应答分支

证券登录应答:

是否是否是是否是否是否是否密码错误密码过期
证券登录应答请求序号是生物识别绑定那 次?只记下会话号,不走界面请求过于频繁?提示稍候重试成功?强制改密?强制改密,不可跳过建议改密?建议改密,可跳过会话号为 0?登录失败需要短信二次认证?进入二次认证页登录成功提示,并解绑该序号对应的 生物识别提示密码已过期

期货登录应答的分支多一些,统一写成表:

应答 处理
生物识别绑定那次的应答 只记下会话号,返回
需要二次认证 按应答里的类型进入短信或邮箱二次认证页,并显示接收地址
没有绑定二次认证信息 不进入二次认证
成功但会话号为 0 当作登录失败
成功 如果当前在二次认证页先退出,再走登录成功
二次认证失败 / 还没请求验证码就去验证 提示认证失败
密码错误 不是交易首页生物识别那次就提示;并解绑该序号对应的生物识别
需要强制改密 进入改密流程
客户状态不允许登录 / 用户不存在 / 其他 提示对应文案

文案不写死在客户端:交易错误码对应的文案表在启动时拉取,按柜台分别查。

4.3 二次认证与改密

期货的二次认证:请求验证码、校验验证码,证券的短信二次认证跳转,各有一个独立页面。

交易网关二次认证页登录管理用户交易网关二次认证页登录管理用户期货登录需要二次认证(短信或邮箱,含接收地址)打开二次认证页点获取验证码请求验证码已发送 / 发送失败(通知)输入验证码校验登录成功退出二次认证页走登录成功

改密有两处细节:

  • 期货强制改密通过再调一次登录完成:登录成功即表示改密成功,长连接把这次的登录应答转给改密流程。
  • 证券强制改密时,如果用户离开了改密页,回来后要再次弹出强制改密框,否则「强制」就形同虚设。

4.4 保活:账户心跳

登录成功后,期货和证券各启动一个 10 秒一次的定时器,跑在全局队列上,带上交易账号和会话号;会话号为空时不发。掉线或登出时停止。

交易网关定时器登录管理交易网关定时器登录管理loop[每 10 秒]登录成功,启动 10 秒定时器到点取交易账号和会话号,任一为空就不发账户心跳掉线或登出,停止

交易会话在客户端没有本地过期时间。会话是否失效完全由网关告知:通过下一节的主推,或者通过任意一条应答里的「账户未登录」「会话校验失败」。

4.5 被挤下线:认出「是不是自己」

单设备在线由网关保证,客户端不做互斥。客户端只做两件事:认出这条通知是不是针对本设备,以及怎么提示。

设备 B交易网关设备 A(已登录)设备 B交易网关设备 A(已登录)同一账户登录登录成功,新会话号证券:重复登录主推(带最新会话号)会话号和本地不同,且本地是已登录下线证券交易会话期货:账户断线主推(带平台、设备标识)平台和设备都是本机,且标记为已断线下线期货交易会话
证券 期货
主推 重复登录 账户断线
先排除 生物识别绑定那次的请求序号 —
判断依据 主推里的会话号是否等于本地会话号 平台 + 设备标识是本机,且「已断线」为真
相同时 本机自己重复登录,忽略 —
应答兜底 「账户未登录」「会话校验失败」,且平台与设备是本机 「账户未登录」「会话校验失败」

期货单点登录、多点登录与掉线处理、登录管理监听证券掉线都按这张表判断;判断「是不是本机」依赖交易信封里的平台与设备标识。

4.6 下线只下线交易

下线做的事很少:交易登录态置否、会话号置空、停掉这一侧的账户心跳。App 账户不动。

提示则看用户当前在哪:

交易行情有没有其他
交易会话下线当前在哪个 Tab?弹「交易登录已掉线」导航栈里有对应的下单页?不打扰用户确认回到交易首页根页面模拟点一下对应账户卡片触发重新登录

交易首页掉线后弹出登录框:确认之后回到交易首页,并模拟点击一次对应的账户卡片,复用卡片点击时的登录逻辑,不用另写一套「重新登录」。


5. 踩过的坑

输错密码,所有设备都弹框。 同一账户在多台设备上时,一台设备输错期货交易密码,网关的失败应答其他设备也会收到,结果别的设备也弹出「密码错误」。修复是记录本机是否真的发起过登录,只有发起过才处理失败应答,并在提示后复位这个记录。

证券登录应答的设备过滤。 证券登录应答曾按平台和设备标识过滤,后来取消了证券登录应答上的设备判断。登出、掉线这类应答仍然比对设备。

静默登录的应答走进了界面分支。 开启生物识别时的绑定登录,应答和普通登录长得一样,不拦截就会走进登录成功、改密、二次认证这些界面分支。收到期货和证券登录应答时先看请求序号,是绑定那次就只记下会话号并返回。

图表页输错密码弹出两个提示。 证券或期货图表页上登录交易,输错密码时,登录管理已经提示过一次,图表页的失败回调又提示了一次。去掉图表页失败回调里的那次提示,失败文案只由登录管理给出。

切换到休眠账户后资金串号。 在交易首页点一个正常账户,弹出登录框后切到休眠账户登录,登录失败后,正常账户显示成了休眠账户的资金。原因是弹窗在登录结果出来之前就把「当前交易账号」改成了待登录的账号。修复是登录前不再改写当前账号,直接用待登录的账号发请求;另外记下上次查询的账号;登录成功之后才查资金并切换首页的账户。

请求过于频繁。 证券登录应答里有「请求过于频繁」的返回,单独认出来,提示稍候重试,而不是当成普通的登录失败。配合入口的 1 秒防重入,减少用户连点带来的重复登录。


6. 对比与取舍

问题 另一种做法 采用的做法 原因
应答处理 每个请求带回调闭包 应答赋给载体属性,观察器处理 主推和应答走同一条路;连接层不懂业务
静默登录与用户登录 两个不同的登录命令 同一个命令,靠请求序号区分 协议里只有一种登录
会话过期 本地记过期时间 不记,由网关告知 交易会话没有下发有效期
被挤下线 下线整个 App 只下线交易会话 两级会话;行情、资讯仍可用
掉线提示 任何页面都弹 只在交易相关页面弹 用户在看资讯时被打断体验差
重新登录 单独的重登流程 回到首页模拟点击账户卡片 复用已有的登录入口

7. 可以改进的地方

下面每一条都是方向,不是已经做完的改动。

现在的做法 问题 改进方向
观察器里写处理逻辑 隐式,测试只能起整条链路 显式的会话状态枚举 + 纯函数 reducer,状态迁移可单测
心跳只发不判 心跳应答丢失时发现不了 连续若干次未收到心跳应答就标记为可疑并主动查询登录状态
期货、证券两套近似的代码 分支多、容易漏 抽象出柜台适配层,共用状态机
「是否本机发起」靠一个记录 并发登录时可能错位 用请求序号精确匹配
模拟点击账户卡片 依赖页面结构 暴露明确的「重新登录某账户」接口
登录
心跳连续无应答查询确认仍在线确认失效被挤 / 会话失效重新登录
未登录认证中待二次认证待改密在线可疑掉线