跳到主要内容

身份验证

MCE 在线层通过 Nakama 支持多种身份验证方法。所有验证流程由 AuthService(位于 Auth/AuthService.cs)和 SessionManager 管理,两者均在启动时由 NakamaManager 自动初始化。

MCE Online 登录界面

该界面随引擎一同提供,涵盖下面的三种流程:邮箱/密码、创建账户以及 SSO 提供商。这里没有任何模型图 —— 这是正在运行的游戏。

连接状态​

ConnectionState 枚举跟踪在线连接的完整生命周期:

状态描述
Disconnected未连接且未尝试连接
Connecting正在尝试建立连接
Connected连接并验证成功
Reconnecting连接丢失,正在尝试自动重连
Offline以离线模式运行(服务器不可用或已禁用)
Failed所有重试后连接失败

您可以通过 NakamaManager.Instance.OnStateChanged 订阅状态变更。

NakamaManager.Instance.OnStateChanged += (state) =>
{
Debug.Log($"Connection state: {state}");
};

NakamaManager 上提供了一些便捷属性:

  • IsConnected — 仅在状态为 Connected 时返回 true。
  • IsOffline — 当状态为 Offline 或 Disconnected 时返回 true。

身份验证方法​

MCE 支持以下 AuthMethod 值:Email、DeviceId、Discord、Google、Apple、Facebook 和 Custom。

设备验证(自动登录)​

最简单的方法。使用 SystemInfo.deviceUniqueIdentifier 自动创建匿名账户。适合移动设备和首次游戏。

bool success = await NakamaManager.Instance.ConnectWithDeviceAsync();

在底层,这是 NakamaManager 唯一的连接流水线,它调用 Client.AuthenticateDeviceAsync(deviceId, create: true):它在首次使用时创建新的 Nakama 账户,并在后续调用中登录。(AuthService 是覆盖在同一条流水线之上的薄外观,因此认证的方式只有一种。)出于隐私考虑,设备 ID 在日志中被截断。

邮箱/密码验证​

支持注册(create: true)和登录(create: false)。

// 注册新账户
bool registered = await NakamaManager.Instance.ConnectWithEmailAsync(
"player@example.com", "securepassword", createAccount: true);

// 登录已有账户
bool loggedIn = await NakamaManager.Instance.ConnectWithEmailAsync(
"player@example.com", "securepassword", createAccount: false);

您也可以通过会返回会话的 AuthService 外观来进行:

OnlineSession session = await NakamaManager.Instance.Auth.AuthenticateEmailAsync(
email, password, create: true);

返回的 OnlineSession 包装了 Nakama 的 ISession,并公开了:UserId、DisplayName、Token、RefreshToken 和 ExpiresAt。

SSO 验证(Discord、Google、Apple)​

SSO 提供程序按提供商在 OnlineConfig 中启用:

  • EnableDiscordSSO(默认:true)
  • EnableGoogleSSO(默认:true)
  • EnableAppleSSO(默认:true)

OAuth 客户端 ID 也在 OnlineConfig 中配置(DiscordClientId、GoogleClientId)。

// Google
bool success = await NakamaManager.Instance.ConnectWithSSOAsync(
AuthMethod.Google, googleIdToken);

// Apple
bool success = await NakamaManager.Instance.ConnectWithSSOAsync(
AuthMethod.Apple, appleIdentityToken);

// Discord(使用 Discord 用户 ID 的自定义验证流程)
bool success = await NakamaManager.Instance.ConnectWithSSOAsync(
AuthMethod.Discord, discordUserId);

Google 和 Apple 使用 Nakama 的内置 AuthenticateGoogleAsync / AuthenticateAppleAsync。Discord 和 Facebook 通过 AuthenticateCustomAsync 路由,因为 Nakama 没有原生的 Discord 认证提供程序。

账户关联​

玩家可以将多种验证方法关联到同一个账户。这允许他们从设备验证开始,之后添加邮箱或 SSO 以实现跨设备访问。

bool linked = await NakamaManager.Instance.Auth.LinkAccountAsync(
AuthMethod.Google, googleToken);

bool linked = await NakamaManager.Instance.Auth.LinkAccountAsync(
AuthMethod.Discord, discordToken);

LinkAccountAsync 根据方法使用 Client.LinkGoogleAsync、Client.LinkAppleAsync 或 Client.LinkCustomAsync。

会话持久化​

SessionManager 使用 PlayerPrefs 处理验证令牌的保存和恢复:

  • 令牌键:mce_nakama_token
  • 刷新令牌键:mce_nakama_refresh

成功验证后,SaveNakamaSession(session) 会持久化两个令牌。在应用重启时,LoadNakamaSession(client) 通过 Nakama.Session.Restore(token, refresh) 恢复会话。如果恢复的会话已过期,则会自动清除。

// 检查是否存在有效会话
bool hasSession = NakamaManager.Instance.SessionMgr.HasValidSession();

// 手动清除会话(登出)
NakamaManager.Instance.SessionMgr.ClearSession();

验证后流程​

在任何成功验证后,NakamaManager.FinalizeConnection() 执行以下序列:

  1. 存储 Session、UserId、DisplayName 和 SessionToken。
  2. 通过 SessionManager 保存会话。
  3. 通过 Client.NewSocket(useMainThread: true) 创建 WebSocket。
  4. 挂钩 Socket 事件:Closed、ReceivedError、ReceivedMatchState、ReceivedChannelMessage、ReceivedNotification、ReceivedMatchmakerMatched、ReceivedStatusPresence。
  5. 使用 Socket.ConnectAsync(session) 连接 Socket。
  6. 异步初始化在线服务:
    • WorldSync.InitializeAsync() — 加入世界匹配。
    • Chat.JoinGlobalChannelAsync() — 加入全局聊天室。
    • Friends.RefreshFriendsListAsync() — 加载好友并关注其状态。
    • Housing.InitializeAsync() — 如果 EnableHousing 已开启。
    • Mods.LoadInstalledModsAsync() — 如果 EnableModSupport 已开启。
  7. 触发 OnConnected 并注册 OnlineCommandBridge。

自动重连​

当 Socket 意外关闭且 OnlineConfig.AutoReconnect 为 true 时,NakamaManager 会自动尝试使用指数退避进行重连:

  • 延迟公式:min(2 * 2^(尝试次数-1), 30) 秒。
  • 最大尝试次数:OnlineConfig.MaxReconnectAttempts(默认:5)。
  • 重连从保存的会话恢复。如果会话已过期,则回退到离线模式。

重连期间状态会转换为 Reconnecting。

离线回退​

当 OnlineConfig.AllowOfflineFallback 为 true(默认值)时,任何连接失败都会优雅地回退到 ConnectionState.Offline。整个游戏继续在本地运行——在线层是完全可选的。

显示名称​

验证后,您可以更新玩家的显示名称:

bool updated = await NakamaManager.Instance.Auth.UpdateDisplayNameAsync("NewName");

错误处理​

验证错误通过 NakamaManager.OnConnectionError 事件传递:

NakamaManager.Instance.OnConnectionError += (errorMessage) =>
{
Debug.LogError($"Connection error: {errorMessage}");
// 向玩家显示错误对话框
};

所有验证方法都在内部捕获异常,并使用 [MCE Online] 或 [Auth] 前缀记录日志。

配置参考​

OnlineConfig(位于 Resources/OnlineConfig 的 ScriptableObject)中的关键设置:

字段默认值描述
ServerHost127.0.0.1Nakama 服务器主机名
ServerPort7350Nakama 服务器端口
ServerKeydefaultkeyNakama 服务器密钥
UseSSLfalse使用 HTTPS/WSS
ConnectionTimeout10超时时间(秒)
AutoReconnecttrue断开时自动重连
MaxReconnectAttempts5最大重试次数
AllowOfflineFallbacktrue失败时回退到离线模式
EnableDiscordSSOtrue启用 Discord 验证
EnableGoogleSSOtrue启用 Google 验证
EnableAppleSSOtrue启用 Apple 验证

安全最佳实践​

  • 切勿在分发的构建中暴露 ServerKey。请使用 Nakama 的环境特定密钥。
  • 生产环境推荐使用 SSO 或邮箱验证。设备验证便于开发和移动端快速启动,但如果设备被清空则无法恢复。
  • 在生产环境中启用 OnlineConfig 中的 EnableServerAuthority。这会将所有状态更改操作(物品、金钱、传送)通过 OnlineCommandBridge 的服务器验证进行路由。
  • 会话令牌存储在 PlayerPrefs 中。在 PlayerPrefs 不安全的平台上(例如 PC),请考虑在静态存储时加密令牌。