5.总结
5.1 知识点
系列按「架构演变 → 票据技术 → 注册 → 登录」铺开:先看单机到分布式再到网关自验证的路线,再学 JWT 与 RSA 在 .NET 里怎么落地,最后两篇把鉴权服里的注册、登录与 Gate 上的验票、会话、顶号串成完整链路。
5.2 核心要点速览
架构角色与三阶段演变
链路上三类进程的职责:
| 角色 | 职责摘要 | 和「按用户名选鉴权」的关系 |
|---|---|---|
| 鉴权服 | 注册、校验密码、签发 JWT;多机时同一用户名固定落到同一台处理 | 这一层做「哈希取模 + position」 |
| Gate | 验 JWT、会话与进游戏前逻辑;顶号、延迟断线、GameAccount 缓存 |
验签在本进程完成 |
| 反向代理 / SLB | 入口流量分拆 | 不替代「用户名 → 某台鉴权」的路由 |
演变对照(中央越答越少,边缘验票越多):
| 维度 | 早期 | 中期 | 现在常见 |
|---|---|---|---|
| 验证靠什么 | 中心库 + 与白名单/游戏服同步 | 鉴权集群 + 共享缓存里的 Token | JWT 声明 + 各 Gate 公钥验签 |
| 扩展与故障面 | 单点易堵 | 缓存仍是热点,同步与一致性要设计 | 横向扩 Gate 相对顺;吊销、过期需单独立项 |
| 常见技术词 | 单体 / 中心鉴权 | 分布式鉴权 + Redis 等 | JWT、OAuth2、微服务网关 |
早期示意是登录成功后往游戏服同步白名单;中期是缓存优先;本系列后半是鉴权签票、Gate 只信签名与声明。
JWT、RSA 与 .NET 侧用法
形态与算法
- 传输形态:
Header.Payload.Signature,前两段是 Base64Url,可解码查看,不是保密字段。 HS256:同一 secret 签与验,实现快;任一验签方泄密即可造假票,多机分发 secret 要慎。RS256:签发侧私钥、验证侧公钥,与「一台鉴权、多台 Gate」常见部署更合拍。
文中类分工
| 类型 | 角色 | 易踩坑 |
|---|---|---|
JwtPayload |
装标准/自定义 claims | exp 与 ValidateLifetime 要一致 |
JwtSecurityToken |
issuer、audience、过期、SigningCredentials |
演示可用 signingCredentials: null,上线不行 |
JwtSecurityTokenHandler |
WriteToken、 ValidateToken、 ReadJwtToken |
异常类型按业务捕获,别一把吞 |
对称:SymmetricSecurityKey + SigningCredentials + HmacSha256;RSA:RsaSecurityKey + RsaSha256。
验证参数
TokenValidationParameters 中与系列代码最相关:ValidateIssuer、ValidateAudience、ValidateLifetime、ValidateIssuerSigningKey,以及 ValidIssuer / ValidAudience / IssuerSigningKey。正文示例会关 ValidateLifetime;线上打开并配合短时效或刷新,否则被盗令牌在过期前都可重放。
密钥格式
| 格式 | 与 C# 导出 |
|---|---|
| PKCS#1 | ExportRSAPublicKey / ExportRSAPrivateKey,结构直接 |
| PKCS#8 | ExportSubjectPublicKeyInfo / ExportPkcs8PrivateKey,可加密保护私钥 |
模长至少 2048;大载荷不宜直接 RSA 加密,签名更合适;数据加密填充宜 OAEP。
签发骨架(对齐正文写法)
var token = new JwtSecurityToken(
issuer: "Tao",
audience: "Tao",
claims: jwtPayload.Claims,
expires: DateTime.UtcNow.AddHours(1),
signingCredentials: signingCredentials
);
return new JwtSecurityTokenHandler().WriteToken(token);
注册:选机、限流、同服准入、并发与缓存
客户端使用 AuthenticationSelectComponent,MurmurHash3(userName) % AuthenticationList.Count 选地址。鉴权节点列表需与服务端配置同源或可热更,否则会出现整批错误路由。
鉴权启动时 AuthenticationComponent.UpdatePosition:读全量鉴权节点配置,得到本机 Position 与 AuthenticationCount。
注册请求过场(顺序即防线顺序):
| 环节 | 作用 |
|---|---|
session.CheckInterval |
限频 |
session.SetTimeout |
会话生命周期 |
| 非空校验 | 用户名 / 密码 |
MurmurHash3(username) % AuthenticationCount 与 Position |
非本 shard 则拒绝 |
同一用户名注册须串行:CoroutineLockComponent + AuthenticationRegisterLock,锁键 username.GetHashCode。内核:注册缓存 → 未命中再查库 → 新建 Account → 写缓存与超时;缓存命中视为已存在。文后虽建议密码加盐哈希,示例或为明文比对,仅用于跟流程。
登录:鉴权发票、客户端拆票、Gate 验票与会话
登录错误码(与注释一致):0 成功;1 参数;2 无账号或密码错;3 非本机 shard。注册示例同样用数字码区分布合法 / 已存在 / 频控或错机,跨接口复用数码时最好落到枚举或文档,避免排障时对不上语义。
登录在 AuthenticationLoginLock 内用 userName + password 作缓存键;命中则直接返回账号 id;否则查库、比对、更新 LoginTime、保存,再挂登录缓存(文中约 5s)。成功后 accountId 对 Gate 列表取模,JWT 中写入 aId、Address、SceneId。
JWTParseComponent 只做分段与 Base64 填充解码,不验签;只为取 Address。Gate 用公钥 ValidateToken,且 GateJWTHelper 要求载荷里 SceneId 与 scene.SceneConfigId 一致,避免错接入口。
Account 在鉴权库;GameAccount 在 Gate 侧(含 SessionRunTimeId),可首次进 Gate 创建。GameAccountManageComponent 做进程内缓存,服务顶号与重连。
顶号与重连:
- 登录成功挂
GameAccountFlagComponent;更新SessionRunTimeId。 - 缓存已有账号则
CancelTimeout;session.RunTimeId == account.SessionRunTimeId视为重复点击,可直接返回。 - 否则用旧
SessionRunTimeId找旧 Session:先清空旧 flag,再通知重复登录、延迟断旧连,避免旧 Session 销毁误伤新连接。 - 销毁路径:
Disconnect查缓存、CancelTimeout、落库、Remove。
实现顺序建议
- 单进程跑通注册 → 登录 → 带 Gate 地址的 JWT,再拆多鉴权与
UpdatePosition。 - 控制台先调通 RSA 签发 + 公钥
ValidateToken,再挂进 Gate RPC。 - 再补限频、position 双检、两把协程锁,最后做 Gate 缓存与顶号。
5.3 面试题精选
基础题
1. 登录流程里错误码 0/1/2/3 各表示什么?和「数字复用」有关的坑是什么?
题目
鉴权返回里 1、2、3 在本系列登录实现中分别对应哪些情况?注册侧也用数字码时,工程上要注意什么?
深入解析
- 登录
Login注释:0成功;1用户名或密码为空;2账号不存在或密码不匹配;3按用户名算出的 shard 不是当前鉴权机,应换机再试。 - 注册侧示例里同样用较小整数表示参数错误、已存在、频控或错机等,若与登录共用一套数字而没有枚举或文档,日志与客户端提示很容易张冠李戴。
- 进阶排障:服务器列表变更后,大量
3往往是客户端与服侧AuthenticationCount/ 节点顺序不一致,而不是用户密码真错了。
答题示例
这篇里登录:0 成功,1 参数不全,2 账号或密码不对,3 这台鉴权不该处理这个用户,要按哈希去别台。
注册也会返回 1、2、3 一类码,若和登录混用同一套数字,最好用枚举或协议文档写死含义,否则运营和客户端会对不上;成片 3 还要怀疑选机和服配置是否同源。
参考文章
- 3.注册流程
- 4.登录流程
进阶题
2. 客户端用 MurmurHash3 选鉴权机,服务端为什么还要用同一公式再算 position?
题目
只信客户端选路,或只在服务端校验,行不行?
深入解析
- 客户端取模:把不同用户名的连接均匀散到多机,减轻单机,属于入口侧负载均衡。
- 服务端用
MurmurHash3(username) % AuthenticationCount与本地Position对齐:不信任客户端;配错地址、被篡改、列表不同步时,在后端直接拒绝,避免写错分片或脏数据。 - 两边必须用同一哈希实现、同一有序节点列表;列表变更要同步配置中心或热更客户端,否则会出现「连上了但一直被 3 拒绝」。
答题示例
客户端哈希是为了分流;服务端再算一遍是为了防伪造路由和配错机,保证只有负责这个用户的那台鉴权能落库。
公式和机器列表必须严格一致,否则用户会觉得密码对也一直失败,其实是 shard 算错了。
参考文章
- 3.注册流程
- 4.登录流程
深度题
3. 客户端只解码 JWT Payload、Gate 才验签,和 SceneId 校验一起解决了什么问题?还有哪些残留风险?
题目
这种分工算不算「信任客户端带的地址」?SceneId 与 SceneConfigId 对不上为什么要拒绝?
深入解析
- 客户端解码只为拿
Address建连;是否允许进服由 Gate 验签决定,不是由客户端解析结果决定。若业务代码把未验签载荷当权限来源,属于实现错误。 SceneId与当前 Gate 配置一致,才能防止拿着给 A 入口签的票去连 B 入口(票仍合法,但连错服)。- 残留风险:载荷可被任何人读取,不要塞隐私;示例未验过期,线上须打开
ValidateLifetime或等价机制;令牌被盗后可在有效期内重放,需 HTTPS、短时效、刷新或踢人策略;登录缓存键若含明文密码,本身也是敏感面,应用安全存储与传输替代设计。
答题示例
客户端只解析 Payload 取 Address,不靠它做鉴权;Gate 验签通过才算数,SceneId 对不上说明票不是给这台 Gate 用的,要拒。
风险主要是别把 Payload 当可信权限、传输要用 TLS、生产要校过期,以及 token 泄露后的重放窗口要靠短效和运营侧吊销或版本控制收口。
参考文章
- 2.JWT
- 4.登录流程
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com