@startuml login-flow !theme plain skinparam backgroundColor #FEFEFE skinparam shadowing false skinparam defaultFontName "Microsoft YaHei" skinparam defaultFontSize 12 ' ============================================================ ' 1. 整体请求处理流程 ' ============================================================ title 1. 整体请求处理流程 |客户端| start :发送请求; |服务端 - Api._initialize| :设备识别 (header/body); :AES-128-ECB 解密 body; if (解密成功?) then (是) :JSON 解析参数; else (否) :尝试明文 input(); endif :MD5 签名校验; if (签名校验通过?) then (是) else (否) :返回 -124 签名拒绝; stop endif switch (路由分发) case (/login/index) :普通登录 index(); case (/login/third) :第三方登录 third(); case (/login/checkToken) :Token 校验 checkToken(); case (/login/logout) :退出登录 logout(); endswitch stop @enduml ' ============================================================ ' 2. 普通登录 index() 流程 ' ============================================================ @startuml login-index !theme plain skinparam backgroundColor #FEFEFE skinparam shadowing false skinparam defaultFontName "Microsoft YaHei" title 2. 普通登录 index() 流程 start :接收参数\nusername, password, imeil,\ngameid, device, channel_id; if (海外游戏 && 国内IP?) then (是) :返回 -110 国内用户禁止登录; stop endif if (参数完整?) then (否) :返回 -100 缺少参数; stop endif if (渠道存在且启用?) then (否) :返回 -120 渠道不存在或已禁用; stop endif if (渠道 level=3?) then (否) :返回 -120 非推广员渠道; stop endif if (游戏存在且未下架?) then (否) :返回 -120 游戏信息不存在; stop endif if (游戏开启登录白名单?) then (是) if (用户在白名单中?) then (否) :返回 -120 当前游戏禁止登录; stop endif endif if (渠道被封禁?) then (是) :返回 -120 渠道禁止登录; stop endif :密码加密 auth_code(password, ENCODE, auth_key); :查询用户 where username + password; if (用户存在?) then (否) :返回 -120 账号不存在或密码不正确; stop endif if (主账号冻结 flag=1?) then (是) :返回 -120 账号已冻结; stop endif if (子账号冻结?) then (是) :返回 -120 子账号已冻结; stop endif :FkStrategiesService 风控策略检查; if (触发风控?) then (是) :返回 -120 风控冻结; stop endif :调用 loginProcess(); stop @enduml ' ============================================================ ' 3. 第三方登录 third() 流程 ' ============================================================ @startuml login-third !theme plain skinparam backgroundColor #FEFEFE skinparam shadowing false skinparam defaultFontName "Microsoft YaHei" title 3. 第三方登录 third() 流程 start :接收参数\nusername(第三方UID), imeil, gameid,\ndevice, channel_id, type_id; if (参数校验通过?) then (否) :返回错误; stop endif if (渠道/游戏校验通过?) then (否) :返回错误; stop endif switch (type_id) case (1 = 微信) :查询 wx_uid; case (2 = QQ) :查询 qq_uid; case (3 = 抖音) :查询 dy_uid; endswitch if (用户已存在?) then (是) :调用 loginProcess(); else (否) :自动生成随机用户名 (11位); :创建账号 (密码固定, fromflag=type); :插入 cy_member_history; :插入 cy_memberstwo 实名扩展; :调用 loginProcess(); endif stop @enduml ' ============================================================ ' 4. loginProcess 公共处理流程 ' ============================================================ @startuml login-process !theme plain skinparam backgroundColor #FEFEFE skinparam shadowing false skinparam defaultFontName "Microsoft YaHei" title 4. loginProcess 公共处理流程 start :接收 userinfo, gameid, imeil, device, channelId; if (IP 被封禁?) then (是) :钉钉告警; :返回 IP禁止登录; stop endif if (IMEI 被封禁?) then (是) :钉钉告警; :返回 设备禁止登录; stop endif if (渠道被封禁?) then (是) :返回 渠道禁止登录; stop endif if (开启防沉迷? isPreventHook==2) then (是) :查询实名信息 MembersTwo + Subaccount; if (中宣部实名认证? game_auth_type==1) then (是) :使用子账号的 auth_status 判断; endif if (未实名 或 未成年人?) then (是) if (法定节假日?) then (是) if (20:00-21:00?) then (是) :设置 offline_time = 21:00; else (否) :返回 未成年限制; stop endif else (否) if (周五/六/日?) then (是) if (20:00-21:00?) then (是) :设置 offline_time = 21:00; else (否) :返回 未成年限制; stop endif else (否) :返回 未成年限制; stop endif endif endif endif :Db::startTrans() 开启事务; if (首次登录该游戏?) then (是) :创建 MemberChannelGame 绑定; :插入玩家游戏渠道绑定记录; else (否) :更新最后登录时间; endif if (子账号已存在 sub_username?) then (是) :更新子账号时间和设备; else (否) :生成 sub_username = userid_APP_STATUS; :创建或更新 Subaccount 记录; endif :MemberDevice::addDevice() 更新设备列表; :Logininfo::limitInsert() 写入登录日志; :saveDevices() 收集设备信息; :更新 Members 最后登录时间; :Db::commit() 提交事务; :生成 Token; note right Token = auth_code( userid|username|gameid| sub_username|随机码|sdk, ENCODE, auth_key ) end note :Redis 存储; note right token → imeil (15天) token|sdk|{userid}|{gameid} → 随机码 (15天) end note if (中宣部防沉迷?) then (是) :Authentication::loginout() 上报登录状态; endif :返回 token, username, sub_username, offline_time; stop @enduml ' ============================================================ ' 5. Token 校验机制 ' ============================================================ @startuml token-check !theme plain skinparam backgroundColor #FEFEFE skinparam shadowing false skinparam defaultFontName "Microsoft YaHei" title 5. Token 校验机制 (checkLogin) start if (在 noNeedLogin 列表中?) then (是) :跳过校验; stop endif :获取 token 和 imeil; if (token 为空?) then (是) :返回 -132 未登录; stop endif :Redis 获取 token→imei; if (Redis 中存在?) then (否) :返回 -133 登录失效; stop endif if (imei 匹配?) then (否) :返回 -134 异地登录; stop endif :解密 token\nauth_code(token, DECODE, auth_key); :提取 userid, username, gameid,\nsub_username, 随机码, type; :Redis 获取 token|{type}|{userid}|{gameid}→随机码; if (随机码存在?) then (否) :删除 token; :返回 -137 登录异常; stop endif if (随机码匹配?) then (否) :删除 token; :返回 -138 登录异常; stop endif :校验通过; :注入 userid, gameid, username, token, sub_username; stop @enduml ' ============================================================ ' 6. 数据模型关系 ' ============================================================ @startuml login-er !theme plain skinparam backgroundColor #FEFEFE skinparam shadowing false skinparam defaultFontName "Microsoft YaHei" title 6. 数据模型关系 (ER 图) entity "Members" as M { *id : int <> -- username : string password : string wx_uid : string qq_uid : string dy_uid : string flag : int channel_id : int reg_time : int login_time : int nickname : string } entity "Subaccount" as S { *id : int <> -- member_id : int <> game_id : int <> sub_username : string channel_id : int auth_status : int real_name : string idcard_num : string auth_pi : string flag : int create_time : int update_time : int last_imeil : string } entity "MemberChannelGame" as MCG { *mcgr_id : int <> -- member_id : int <> game_id : int <> channel_id : int <> mcgr_imeil : string mcgr_ip : string mcgr_createtime : int update_time : int } entity "MembersTwo" as MT { *id : int <> -- userid : int <> username : string realname : string idcard : string create_time : int } entity "Logininfo" as LI { *id : int <> -- userid : int <> sub_id : int gameid : int imeil : string device : int channel_id : int login_time : int ip : string } entity "Game" as G { *id : int <> -- name : string cooperation_status : int is_login : int game_auth_type : string game_bizid : string } entity "Channel" as C { *id : int <> -- name : string mark : string level : int status : int } entity "GameBanned" as GB { *id : int <> -- game_id : int <> banned_type : string banned_device : string } entity "GameRestrict" as GR { *id : int <> -- game_id : int <> restrict_type : string restrict_status : int } entity "MemberDevice" as MD { *id : int <> -- member_id : int <> game_id : int <> imeil : string device : int } M ||--o{ S : "1:N 子账号" M ||--o{ MCG : "1:N 游戏绑定" M ||--o{ LI : "1:N 登录日志" M ||--o| MT : "1:1 实名信息" M ||--o{ MD : "1:N 设备记录" G ||--o{ S : "1:N" G ||--o{ GB : "1:N 封禁" G ||--o{ GR : "1:N 防沉迷" C ||--o{ MCG : "1:N" @enduml