搭配BaaS授权使用游戏内商店
您可以搭配BaaS授权系统使用游戏内商店来销售游戏内商品。该方案的交互过程如下:
- 用户通过BaaS授权系统登录您的应用程序。
- BaaS服务通过传入用户ID向艾克索拉服务器请求用户Web令牌(JWT)。
- 艾克索拉服务器向BaaS服务返回用户JWT。
- BaaS服务将用户JWT传给应用程序。
- 应用程序使用API通过用户JWT与艾克索拉服务器交互。
注:
如果您未实现用户授权的逻辑,可集成艾克索拉登录管理器并在PlayFab或Firebase中设置用户数据的存储。这样您就可以使用Login API来认证用户身份并接收JWT来与其他艾克索拉产品的API交互。
- 在发布商帐户中,将标准登录管理器项目连接到您的项目。
- 设置服务器OAuth 2.0客户端。
- 按照Firebase和PlayFab的说明将现成函数添加到您的项目。
设置服务器OAuth 2.0客户端
- 在发布商帐户中打开您的项目,然后前往登录管理器部分。
- 在登录管理器项目面板中单击配置。
- 前往安全性区块,然后选择OAuth 2.0部分。
- 单击添加OAuth 2.0。
- 指定OAuth 2.0重定向URI。
- 勾选服务器(服务器对服务器连接)复选框。
- 单击连接。
- 复制并保存客户端ID和密钥。
向Firebase项目添加云函数
- 初始化您的Firebase项目。
- 导入并配置用户JWT的接收函数,其中:
<ProjectID>
是项目ID,可在您发布商帐户中项目名称的旁边找到。<LoginID>
是登录管理器ID,获取方式是打开发布商帐户,前往登录管理器 > 仪表板 > 您的登录管理器项目部分,然后单击登录管理器项目名称旁边的复制ID。<OAuthClientID>
是设置服务器OAuth 2.0客户端时收到的客户端ID。<OAuthSecretKey>
是设置服务器OAuth 2.0客户端时收到的密钥。
接收用户JWT的函数代码:
Copy
- javascript
const projectId = "<ProjectID>";
const loginProjectId = "<LoginID>";
const serverOauthClientId = <OAuthClientID>;
const serverOauthClientSecret = "<OAuthSecretKey>";
exports.getXsollaLoginToken = functions.https.onCall((data, context) => {
if (!context.auth) {
throw new functions.https.HttpsError(
"failed-precondition",
"The function must be called while authenticated."
);
}
const postData =
"grant_type=client_credentials" +
`&client_secret=${serverOauthClientSecret}`+
`&client_id=${serverOauthClientId}`;
const options = {
hostname: "login.xsolla.com",
port: 443,
path: "/api/oauth2/token",
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
"Content-Length": postData.length,
},
};
return new Promise( (resolve, reject) => {
const req = https.request(options, (res) => {
if (res.statusCode !== 200) {
reject(
new functions.https.HttpsError(
"internal",
"Server token not received"
)
);
}
let body = [];
res.on("data", (d) => {
body.push(d);
});
res.on("end", () => {
try {
body = JSON.parse(Buffer.concat(body).toString());
} catch (e) {
reject(
new functions.https.HttpsError(
"internal",
"Malformed server token response"
)
);
}
getClientToken(context.auth.uid, body.access_token, resolve, reject);
});
});
req.on("error", (e) => {
reject(new functions.https.HttpsError(
"internal",
"Internal error while server token flow"
));
});
req.write(postData);
req.end();
});
});
// eslint-disable-next-line require-jsdoc
function getClientToken(userId, serverToken, resolve, reject) {
const postData = JSON.stringify(
{
"server_custom_id": userId,
}
);
const path =
"/api/users/login/server_custom_id?" +
`projectId=${loginProjectId}&` +
`publisher_project_id=${projectId}`;
const options = {
hostname: "login.xsolla.com",
port: 443,
path: path,
method: "POST",
headers: {
"Content-Type": "application/json",
"Content-Length": postData.length,
"X-Server-Authorization": serverToken,
},
};
const req = https.request(options, (res) => {
if (res.statusCode !== 200) {
reject(
new functions.https.HttpsError(
"internal",
"Client token not received"
)
);
}
let body = [];
res.on("data", (d) => {
body.push(d);
});
res.on("end", () => {
try {
body = JSON.parse(Buffer.concat(body).toString());
} catch (e) {
reject(
new functions.https.HttpsError(
"internal",
"Malformed client token response"
)
);
}
resolve({
"token": body.token,
});
});
});
req.on("error", (e) => {
reject(new functions.https.HttpsError(
"internal",
"Internal error while client token flow"
));
});
req.write(postData);
req.end();
}
- 参照此示例将该函数部署到生产环境。
- 添加客户端侧逻辑从您的应用程序调用函数。将
getXsollaLoginToken
指定为函数名称。传参为非必需。 - 在应用程序中,自行实现与API交互的方法或使用艾克索拉SDK。
向PlayFab项目添加云脚本
- 创建包含用户JWT接收函数的JS文件,其中:
<ProjectID>
是项目ID,可在您发布商帐户中项目名称的旁边找到。<LoginID>
是登录管理器ID,获取方式是打开发布商帐户,前往登录管理器 > 仪表板 > 您的登录管理器项目部分,然后单击登录管理器项目名称旁边的复制ID。<OAuthClientID>
是设置服务器OAuth 2.0客户端时收到的客户端ID。<OAuthSecretKey>
是设置服务器OAuth 2.0客户端时收到的密钥。
注:
如果已在项目中使用了云脚本,请将接收用户JWT的函数添加到该代码的末尾。
Copy
- javascript
handlers.GetXsollaLoginToken = function (args) {
// TODO replace with production credentials
const projectId = <ProjectID>;
const loginProjectId = "<LoginID>";
const serverOauthClientId = <OAuthClientID>;
const serverOauthClientSecret = "<OAuthSecretKey>";
const getServerTokenBody =
"grant_type=client_credentials" +
`&client_secret=${serverOauthClientSecret}` +
`&client_id=${serverOauthClientId}`;
const serverTokenResponse = JSON.parse(
http.request(
"https://login.xsolla.com/api/oauth2/token",
"post",
getServerTokenBody,
"application/x-www-form-urlencoded",
{})
);
let serverToken = ""
if ('access_token' in serverTokenResponse) {
serverToken = serverTokenResponse.access_token;
} else {
return {
"error_message": "Server token not received"
}
}
const getUserTokenHeaders = {
"X-Server-Authorization": serverToken
}
const getUserTokenBody = JSON.stringify(
{
"server_custom_id": currentPlayerId,
}
);
const getUserTokenPath =
"/api/users/login/server_custom_id?" +
`projectId=${loginProjectId}&` +
`publisher_project_id=${projectId}`;
const userTokenResponse = JSON.parse(
http.request(
"https://login.xsolla.com" + getUserTokenPath,
"post",
getUserTokenBody,
"application/json",
getUserTokenHeaders)
);
if ('token' in userTokenResponse) {
return {
"token": userTokenResponse.token
}
} else {
return {
"error_message": "User token not received"
}
}
}
- 前往PlayFab项目设置。
- 上传云脚本文件。
- 在生产环境中运行云脚本。
- 添加客户端侧逻辑从应用程序调用函数。将
GetXsollaLoginToken
指定为函数名。传参为非必需。
调用用户JWT接收函数的示例:
Copy
kotlin
- kotlin
- C#
- C++
val tokenRequest = PlayFabClientModels.ExecuteCloudScriptRequest()
tokenRequest.FunctionName = "GetXsollaLoginToken"
val res = PlayFabClientAPI.ExecuteCloudScript(tokenRequest)
val result = res.Result.FunctionResult as Map<*, *>
val token = result["token"]
val errorMessage = result["error_message"]
var tokenRequest = new ExecuteCloudScriptRequest{
FunctionName = "GetXsollaLoginToken"
};
PlayFabClientAPI.ExecuteCloudScript(
tokenRequest,
scriptResult =>
{
var functionResult = scriptResult.FunctionResult as Dictionary<string, string>;
var token = functionResult["token"];
},
playfabError => { Debug.LogError($"GetXsollaAccessToken error: {playfabError.ErrorMessage}"); });
void UMyClass::GetXsollaToken()
{
FClientExecuteCloudScriptRequest tokenRequest;
tokenRequest.FunctionName = TEXT("GGetXsollaLoginToken");
UPlayFabClientAPI::FDelegateOnSuccessExecuteCloudScript onSuccess;
onSuccess.BindUFunction(this, "OnTokenRecieved");
UPlayFabClientAPI::FDelegateOnFailurePlayFabError onFailure;
onSuccess.BindUFunction(this, "OnError");
UPlayFabClientAPI::ExecuteCloudScript(tokenRequest, onSuccess, onFailure, nullptr);
}
void UMyClass::OnTokenRecieved(FClientExecuteCloudScriptResult result, UObject* customData)
{
const FString& token = result.FunctionResult->GetStringField(TEXT("token"));
// do something with a token
}
void UMyClass::OnError(FPlayFabError error, UObject* customData)
{
// handle errors
}
注:
本例中使用PlayFab SDK方法向云脚本发送请求。您也可以不在项目中添加PlayFab SDK,而是自行实现请求和响应过程。
本文对您的有帮助吗?
感谢您的反馈!
我们会查看您的留言并运用它改进用户体验。有用链接
上次更新时间: 2024年10月3日发现了错别字或其他内容错误? 请选择文本,然后按Ctrl+Enter。