探探的多账号登录是怎么实现的?(二)

472 阅读7分钟

探探的多手机号账号系统(如A、B两个手机号分别注册独立账号)核心目标是实现账号身份隔离​(不同手机号对应独立用户数据)和便捷的登录选择​(登录界面快速切换已绑定的手机号)。以下从账号体系设计登录流程数据隔离机制三个核心维度拆解设计原理:


一、账号体系设计:手机号与用户身份的强绑定

探探的核心账号标识是全局唯一的 user_id(如UUID或自增主键),但手机号作为用户的强身份凭证,与 user_id 建立一一对应关系。具体设计如下:

1. 注册阶段:手机号与user_id的绑定

  • 注册流程​:用户输入手机号→系统发送短信验证码→验证通过后,系统为该手机号生成唯一的 user_id,并在数据库中记录 手机号 ↔ user_id 的映射关系。

    • 示例数据库表(简化版):

      sql
      复制
      -- 用户主表(核心身份信息)
      CREATE TABLE users (
        user_id VARCHAR(36) PRIMARY KEY,  -- 全局唯一标识
        phone VARCHAR(11) UNIQUE NOT NULL,  -- 手机号(唯一约束,确保一个手机号只能注册一个账号)
        username VARCHAR(64),  -- 昵称(可修改)
        avatar_url VARCHAR(255),  -- 头像(可修改)
        created_at TIMESTAMP  -- 注册时间
      );
      
      -- 扩展信息表(如隐私设置、账号状态)
      CREATE TABLE user_profile (
        user_id VARCHAR(36) PRIMARY KEY,
        is_phone_verified BOOLEAN DEFAULT TRUE,  -- 手机号是否已验证(默认已验证)
        last_login_time TIMESTAMP,  -- 最后登录时间
        FOREIGN KEY (user_id) REFERENCES users(user_id)
      );
      
    • 关键约束​:users.phone 字段设置唯一索引,确保一个手机号只能注册一个账号(避免重复注册)。

2. 多手机号支持:单账号绑定多手机号(可选扩展)​

探探可能允许用户在一个主账号下绑定多个手机号(如“添加备用手机号”),但本题场景是两个独立手机号注册两个独立账号,因此每个手机号对应唯一的 user_id,无交叉绑定。


二、登录界面:手机号列表的展示与选择

用户打开登录界面时,系统需展示已绑定的手机号列表(如A、B两个手机号),核心逻辑如下:

1. 客户端获取已绑定手机号

  • 首次登录前​:若用户未注册过任何账号,登录界面无手机号列表;若用户已注册过至少一个手机号账号,客户端需从服务端获取已绑定的手机号列表。

  • 服务端接口​:客户端调用 /api/get_bound_phones 接口,服务端根据当前设备的登录态(若有)或匿名Token返回已绑定的手机号(仅属于当前用户的手机号)。

    • 示例响应:

      json
      复制
      {
        "code": 200,
        "data": {
          "phones": ["13812345678", "13987654321"]  // A、B手机号
        }
      }
      

2. 界面交互:手机号选择与登录凭证输入

  • 展示方式​:登录界面显示已绑定的手机号列表(如“选择已注册的手机号”),用户点击某个手机号后,进入验证码输入页(或密码页,若账号已设置密码)。
  • 未绑定手机号的新用户​:若用户需注册新账号,点击“新用户注册”,输入新手机号并完成验证,生成新的 user_id 并绑定该手机号。

三、登录流程:手机号验证与账号身份确认

用户选择手机号并输入验证码(或密码)后,服务端需验证该手机号对应的 user_id,并生成会话Token。具体流程如下:

1. 验证手机号的有效性

  • 服务端接收客户端提交的手机号(如13812345678)和短信验证码。
  • 校验验证码是否匹配:查询短信验证码服务(如阿里云短信)的缓存或数据库,确认该手机号收到的验证码是否与用户输入一致,且未过期。

2. 关联手机号与user_id

  • 验证通过后,服务端通过 users 表的 phone 字段查询对应的 user_id(如13812345678对应 user_id=A)。
  • 若手机号未注册(如用户首次使用该手机号),则进入注册流程(生成新 user_id,绑定手机号)。

3. 生成会话Token

  • 登录成功后,服务端为用户生成 access_token(短期有效,如30分钟)和 refresh_token(长期有效,如7天),并将 token 与 user_id 绑定存储(如Redis)。

    • Redis存储示例:

      markdown
      复制
      key: token:{access_token}  value: {user_id: A, expire: 1620000000}
      key: token:{refresh_token}  value: {user_id: A, expire: 1627680000}
      

4. 登录态传递

  • 客户端后续所有请求(如获取好友列表、聊天记录)需在请求头携带 Authorization: Bearer {access_token}
  • 服务端通过 access_token 从Redis中查询对应的 user_id(如A),确保用户只能访问自己 user_id 关联的数据。

四、数据隔离:基于user_id的资源隔离

两个手机号(A、B)对应两个独立账号的核心是所有用户数据均以user_id为唯一标识,确保数据互不干扰。具体实现如下:

1. 数据库表设计:user_id作为主键或外键

  • 所有用户相关数据(如聊天记录、好友列表、个人资料)的表均以 user_id 作为关联字段,确保数据归属明确。

    • 示例表(聊天记录):

      sql
      复制
      -- 聊天消息表
      CREATE TABLE messages (
        message_id BIGINT PRIMARY KEY AUTO_INCREMENT,
        sender_id VARCHAR(36) NOT NULL,  -- 发送方user_id(关联users表)
        receiver_id VARCHAR(36) NOT NULL,  -- 接收方user_id
        content TEXT,
        sent_time TIMESTAMP,
        FOREIGN KEY (sender_id) REFERENCES users(user_id),
        FOREIGN KEY (receiver_id) REFERENCES users(user_id)
      );
      
    • 隔离效果​:A账号的 user_id=A 发送的消息仅关联到A的聊天记录,B账号的 user_id=B 无法访问A的消息。

2. 接口权限控制:基于user_id的鉴权

  • 所有涉及用户数据的接口(如获取个人信息、修改头像)需校验 user_id 与请求发起者的Token是否匹配。

    • 示例逻辑(伪代码):

      python
      复制
      def get_user_profile(request):
          access_token = request.headers.get("Authorization")
          user_id = redis.get(f"token:{access_token}")  # 从Token获取user_id
          if not user_id:
              return {"code": 401, "msg": "未登录"}
          # 查询该user_id对应的用户资料
          profile = db.query("SELECT * FROM user_profile WHERE user_id = %s", user_id)
          return {"code": 200, "data": profile}
      

3. 存储隔离:物理或逻辑隔离(可选)​

  • 对于高安全需求场景(如金融类数据),探探可能采用分库分表策略,将不同 user_id 段的数据存储在不同数据库实例中(如A账号在DB1,B账号在DB2),进一步降低数据混淆风险。
  • 普通场景下,通过 user_id 字段关联即可实现逻辑隔离,无需物理分离。

五、关键技术挑战与解决方案

挑战1:手机号重复注册

  • 问题​:用户可能尝试用已注册的手机号再次注册。
  • 解决​:服务端在注册时校验 users.phone 的唯一性约束(数据库抛唯一索引错误),返回“该手机号已注册”提示。

挑战2:登录态跨设备同步

  • 问题​:用户在手机1用A手机号登录,手机2用B手机号登录,需确保两个设备的Token独立且互不影响。
  • 解决​:每个Token与 user_id 强绑定,不同设备的Token在Redis中独立存储(无冲突),旧设备Token失效仅影响当前设备。

挑战3:数据误操作(如A误删B的好友)​

  • 问题​:因数据隔离,A无法访问B的好友列表,误操作概率极低。
  • 解决​:所有数据操作接口强制校验 user_id 与资源归属(如删除好友时,校验好友关系的 user_id 是否为当前登录用户)。

总结

探探多手机号账号系统的核心设计原理可概括为:

  1. 强绑定手机号与user_id​:通过数据库唯一约束确保一个手机号对应唯一账号;
  2. Token与user_id关联​:登录态通过Token标识用户身份,所有请求基于user_id隔离数据;
  3. 接口级权限控制​:所有数据操作强制校验user_id归属,确保数据互不干扰。

这一设计既保证了用户通过手机号快速选择登录的便捷性,又通过严格的隔离机制确保了不同账号数据的独立性和安全性。