客户端接入
本文将介绍如何在游戏客户端实现 Player Network SDK 的登录鉴权功能,列出了相关接口及其使用指南,请根据所使用的游戏引擎选择相应的集成方式。
在使用登录鉴权接口之前,您必须已经接入 Player Network SDK, 详情可参考 Player Network SDK 接入 - Unity 或 Player Network SDK 接入 - Unreal
登录流程
客户端的接入 流程图中 1、2、3、4、5 是游戏客户端需要完成的,其中
- 步骤1:接入并初始化 SDK
- 步骤2:调用自动登录接口
- 步骤3:处理自动登录回调
- 步骤4:手动调用特定的渠道进行登录
- 步骤5:处理手动登录回调
后台的接入 流程图中的 步骤6 需要游戏研发完成,其中:
- 步骤6:游戏客户端传递登录数据给游戏后台,游戏后台到 PNTSDK 后台进行鉴权,处理游戏后台返回的鉴权结果。游戏后台到 PNTSDK 后台的鉴权步骤,可参考 后台接入指引,调用鉴权接口可参考 /v2/auth/verify_login。
自动登录
开发人员可以通过调用 AutoLogin 接口来实现玩家自动登录。此接口使用本地缓存中存储的登录态,通过将此登录态和后台信息比对来验证玩家身份。如果本地缓存中没有登录态,或者后台无法验证传递的登录态,则自动登录失败。在自动登录失败的情况下,开发人员需要调用 Login 接口使玩家手动登录。
- Unity
- Unreal Engine
INTLAPI.AutoLogin();
具体使用方法可参考 Unity 自动登录
UINTLSDKAPI::AutoLogin();
具体使用方法可参考 UE 自动登录
手动登录
手动登录可分为第三方渠道登录和游客登录两种方式。第三方渠道登录指玩家通过社交渠道账号登录游戏,游客登录指玩家无需注册账号即可登录游戏。
手动登录需要调用 Login 接口,调用此接口时需传递登录渠道、登录渠道要求的权限以及登录渠道要求的其他信息作为入参参数。关于各个登录渠道要求的权限及额外参数信息,请参考各个登录渠道的接入指引。
第三方渠道登录
渠道登录通过 Login 接口打开第三方渠道页面,要求玩家输入第三方身份信息,完成登录操作。登录成功后,通常会有授权页,要求玩家同意游戏获取其第三方渠道账号信息(如用户名、头像、邮箱等)。如果玩家同意授权,第三方渠道将返回用户的 UID 和其他信息,供 Player Network SDK 鉴权使用,从而实现玩家登录游戏。
Player Network SDK 封装了主流第三方社交平台的接入逻辑,支持快速鉴权并提取用户信息,屏蔽了各个渠道间的接入差异,极大地降低了集成成本。游戏团队可根据业务需求,自由配置支持的渠道及其显示顺序。
下面的代码以 Facebook 渠道登录为例。
- Unity
- Unreal Engine
更多关于 Player Network SDK 已支持的渠道信息,可参考三方渠道接入教程。
游客登录
游客登录在部分市场(如日本)广受欢迎,游客登录无需玩家注册账号即可快速体验游戏内容,降低了玩家的准入门槛。但是,游客账号是不稳定的,可能会造成游戏数据丢失,同时也不方便进行账号查找等操作,不方便客服协助解决账号问题。建议游戏在后续的过程中,提醒玩家进行游客账号绑定社交账号。
- Unity
- Unreal Engine
INTLAPI.Login(INTLChannel.Guest);
UINTLSDKAPI::Login(EINTLLoginChannel::kChannelGuest);
Player Network SDK 允许游客账号使用引继码从一个设备转移到另一个设备而不丢失任何游戏数据。例如,玩家在设备 A 上使用 OpenID A 登录游戏,设置游戏账号密码并生成引继码。
- Unity
- Unreal Engine
INTLAPI.GenerateTransferCode("password");
UINTLSDKAPI::GenerateTransferCode("password");
然后,在设备 B 上输入密码和引继码。这样,他们就能在设备 B 上登录游戏,从而有效地转移了游客账号。现在,设备 B 上的游戏账号已与 OpenID A 绑定,表明引继成功。
- Unity
- Unreal Engine
INTLAPI.TransferAccount("transferCode","password");
UINTLSDKAPI::TransferAccount("transferCode","password");
有关于游客账号的实现逻辑和更多细节,请参考 游客账号 。
账号绑定与解绑
绑定账号
当玩家使用游客渠道登录时,游戏可以推荐玩家绑定社交渠道账号,以避免游客账号丢失。当玩家使用第三方社交渠道登录时,也可以绑定其他社交渠道的账号。绑定关系存在于渠道和 openid 之间,位于游戏内部,而不是跨游戏的。
下图展示了账号绑定的逻辑:
要绑定账号,玩家首先需要成功登录游戏。然后,开发人员调用 Bind 接口。此接口的入参参数包括玩家想要绑定的登录渠道的渠道定义、被绑渠道需要的权限以及指定的额外信息。关于每个渠道需要的权限及额外信息,请参考各个登录渠道的接入指引。
同一渠道下只有一个 UID 可以绑定到一个 OpenID。例如,一个 OpenID 不能同时绑定两个不同的 Facebook UIDs,一个 Facebook UID 也不能同时绑定两个不同的 Openids。如果被绑账号返回的 UID 无法绑定 OpenID,Player Network 后台将返回错误代码。此错误代码可能表示
- 被绑账号返回的 UID 已经绑定了其他 OpenID
- 登录账号的 OpenID 已经绑定了同渠道的另一个 UID
在调用 Bind 方法时,如果当前的登录渠道是游客账号,则此游客账号可以绑定任意其他登录渠道。然而,如果玩家登录的不是游客账号,则此账号仅可以绑定其他非游客账号的登录渠道,不可绑定游客渠道。
下面的示例代码以 Facebook 为例。
- Unity
- Unreal Engine
解绑账号
开发人员可以将 OpenID 和登录渠道解绑。成功解绑后,玩家将无法再使用未绑定的账号登录游戏。玩家下次尝试使用未绑定的账号登录时,将生成一个新的 OpenID。
要解绑玩家账号,开发者需要调用 Unbind 接口,并传递包括需要解绑的渠道 ID 及两个可选参数作为接口入参,即解绑渠道的 UID 和解绑渠道需要的其他数据。
下面的示例代码以解绑 Facebook 渠道为例。
- Unity
- Unreal Engine
登出游戏
开发人员可通过调用 Logout 接口为玩家提供从当前登录渠道登出游戏的选项。玩家从当前登录渠道中登出后,本地缓存中存储的登录态将会被清除,玩家下次登录时无法自动登录,只能手动登录。
代码示例
下面的代码展示了如何在游戏客户端中添加/移除登录鉴权相关的回调,并处理登录、自动登录、绑定、登出和解绑函数的回调结果,仅供参考。
- Unity
- Unreal Engine
// Suggestion : Add observers when the game starts
public void AddObserver()
{
INTLAPI.AddAuthBaseResultObserver(OnAuthBaseResultEvent);
INTLAPI.AddAuthResultObserver(OnAuthResultEvent);
}
public void RemoveObserver()
{
INTLAPI.RemoveAuthBaseResultObserver(OnAuthBaseResultEvent);
INTLAPI.RemoveAuthResultObserver(OnAuthResultEvent);
}
// Process the callback of AuthResultObserver, including login, autologin, bind
private void OnAuthResultEvent(INTLAuthResult AuthResult)
{
switch (AuthResult.MethodId)
{
case (int)INTLMethodID.INTL_AUTH_LOGIN:
if(AuthResult.RetCode == (int)ERROR_CODE.SUCCESS) {
Debug.Log("Login success");
}
break;
case (int)INTLMethodID.INTL_AUTH_AUTOLOGIN:
if(AuthResult.RetCode == (int)ERROR_CODE.SUCCESS) {
Debug.Log("Autologin success");
} else {
Debug.Log("Autologin failed, ret_code = " + AuthResult.RetCode + ", ret_msg = " + AuthResult.RetMsg);
// Call login after autologin failed
INTLAPI.Login(INTLChannel.Guest);
}
break;
case (int)INTLMethodID.INTL_AUTH_BIND:
if(AuthResult.RetCode == (int)ERROR_CODE.SUCCESS) {
Debug.Log("Bind success");
}
break;
default:
break;
}
}
// Process the callback of AuthBaseResultObserver, including logout, unbind
public void OnAuthBaseResultEvent(INTLBaseResult ret)
{
if (ret.MethodId == (int)INTLMethodID.INTL_AUTH_LOGOUT) {
Debug.Log("Logout success");
} else if (ret.MethodId == (int)INTLMethodID.INTL_AUTH_UNBIND) {
Debug.Log("Unbind success");
}
}
// Suggestion : Add observers when the game starts
void AddObserver()
{
FINTLAuthBaseEvent authBaseObserver;
FINTLAuthEvent authObserver;
authObserver.AddUObject(this, &UAuthWindow::OnAuthResult_Implementation);
authBaseObserver.AddUObject(this, &UAuthWindow::OnAuthBaseResult_Implementation);
UINTLSDKAPI::SetAuthBaseResultObserver(authBaseObserver);
UINTLSDKAPI::SetAuthResultObserver(authObserver);
}
void RemoveObserver()
{
UINTLSDKAPI::GetAuthBaseResultObserver().Clear();
UINTLSDKAPI::GetAuthResultObserver().Clear();
}
// Process the callback of AuthResultObserver, including login, autologin, bind
void OnAuthResult_Implementation(FINTLAuthResult ret)
{
switch(ret.MethodId)
{
case (int32)kMethodIDAuthLogin:
if(ret.RetCode == INTL_NAMESPACE::ErrorCode::SUCCESS) {
UE_LOG(LogTemp, Warning, TEXT("Login success"));
}
break;
case (int32)kMethodIDAuthAutoLogin:
if(ret.RetCode == INTL_NAMESPACE::ErrorCode::SUCCESS) {
UE_LOG(LogTemp, Warning, TEXT("Autologin success"));
} else {
UE_LOG(LogTemp, Warning, TEXT("Autologin failed, ret_code = %d, ret_msg = %s"), ret.RetCode, *ret.RetMsg);
// Call login after autologin failed
UINTLSDKAPI::Login(EINTLLoginChannel::kChannelGuest);
}
break;
case (int32)kMethodIDAuthBind:
if(ret.RetCode == INTL_NAMESPACE::ErrorCode::SUCCESS) {
UE_LOG(LogTemp, Warning, TEXT("Bind success"));
}
break;
default:
break;
}
}
// Process the callback of AuthBaseResultObserver, including logout, unbind
void OnAuthBaseResult_Implementation(FINTLBaseResult ret)
{
if (ret.MethodId == (int32)kMethodIDAuthLogout) {
UE_LOG(LogTemp, Warning, TEXT("Logout success"));
} else if (ret.MethodId == (int32)kMethodIDAuthUnbind) {
UE_LOG(LogTemp, Warning, TEXT("Unbind success"));
}
}