BaaS 권한 부여를 이용해 인게임 스토어 사용

인게임 아이템 판매에 인게임 스토어를 BaaS 권한 부여 시스템과 함께 사용할 수 있습니다. 이 경우의 상호 작용은 다음과 같습니다.

  1. 사용자가 BaaS 인증 시스템을 통해 귀하의 애플리케이션에 로그인합니다.
  2. BaaS 서비스는 사용자 ID를 전달하여 엑솔라 서버로부터 사용자 JSON 웹 토큰(JWT)을 요청합니다.
  3. 엑솔라 서버는 사용자 JWT를 BaaS 서비스에 반환합니다.
  4. BaaS 서비스는 사용자 JWT를 애플리케이션에 전달합니다.
  5. 애플리케이션은 사용자 JWT를 사용하여 API를 사용하는 엑솔라 서버와 상호 작용합니다.

알림
사용자 인증용 로직을 구현하지 않은 경우 엑솔라 로그인을 통합하고 PlayFab 또는 Firebase에서 사용자 데이터의 저장소를 설정할 수 있습니다. 이를 통해 로그인 API를 사용하여 사용자를 인증하고 JWT를 수신하여 다른 엑솔라 제품의 API와 상호 작용할 수 있습니다.

사용자 JWT를 가져오려면:

  1. 게시자 계정에서 표준 로그인 프로젝트를 자신의 프로젝트에 연결합니다.
  2. 서버 OAuth 2.0 클라이언트를 설정합니다.
  3. FirebasePlayFab용 지침에 따라 프로젝트에 미리 만들어진 함수를 추가합니다.

서버 OAuth 2.0 클라이언트 설정

  1. 게시자 계정에서 프로젝트를 열고 로그인 섹션으로 이동합니다.
  2. 로그인 프로젝트의 패널에서 구성을 클릭합니다.
  3. 보안 블록으로 이동한 후 OAuth 2.0 섹션을 선택합니다.
  4. OAuth 2.0 추가를 클릭합니다.
  5. OAuth 2.0 리디렉션 URI를 지정합니다.
  6. 서버(서버 간 연결) 상자를 선택 표시합니다.
  7. 연결을 클릭합니다.
  8. 클라이언트 ID와 비밀 키를 복사하여 저장합니다.

클라우드 기능을 Firebase 프로젝트에 추가

  1. Firebase 프로젝트를 초기화합니다.
  2. 사용자 JWT 기능에 대한 수신 기능을 가져오고 구성합니다. 여기에서:
    • <ProjectID>는 프로젝트 ID이며 프로젝트 이름 옆의 게시자 계정에서 확인할 수 있습니다.
    • <LoginID>는 로그인 ID이며 로그인 > 대시보드 섹션으로 이동하고 로그인 프로젝트 이름 옆에 있는 ID 복사를 클리한 후 게시자 계정을 열어 가져올 수 있습니다.
    • <OAuthClientID>서버 OAuth 2.0 클라이언트를 설정할 때 받은 클라이언트 ID입니다.
    • <OAuthSecretKey>서버 OAuth 2.0 클라이언트를 설정할 때 받은 비밀 키입니다.

사용자 JWT 수신용 함수 코드:

Copy
Full screen
Small screen
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();
}

  1. 이 예시를 따라 프로덕션 환경에 함수를 배포합니다.
  2. 애플리케이션에서 함수를 호출할 클라이언트 측 논리를 추가합니다. getXsollaLoginToken을 함수 이름으로 지정합니다. 매개 변수 전달은 하지 않아도 됩니다.
  3. 애플리케이션에서 API를 이용해 자체적으로 작업하거나 엑솔라 SDK를 이용해 작업할 메소드를 구현합니다.

클라우드 스크립트를 PlayFab 프로젝트에 추가

  1. 사용자 JWT 수신용 함수 코드를 사용하여 JS 파일을 생성합니다. 여기에서
    • <ProjectID>는 프로젝트 ID이며 프로젝트 이름 옆의 게시자 계정에서 확인할 수 있습니다.
    • <LoginID>는 로그인 ID이며 로그인 > 대시보드 섹션으로 이동하고 로그인 프로젝트 이름 옆에 있는 ID 복사를 클리한 후 게시자 계정을 열어 가져올 수 있습니다.
    • <OAuthClientID>서버 OAuth 2.0 클라이언트를 설정할 때 받은 클라이언트 ID입니다.
    • <OAuthSecretKey>서버 OAuth 2.0 클라이언트를 설정할 때 받은 비밀 키입니다.

알림
프로젝트에서 클라우드 스크립트를 이미 사용 중인 경우 코드 끝에 사용자 JWT 수신용 함수를 추가합니다.

사용자 JWT 수신용 함수 코드:

Copy
Full screen
Small screen
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"
        }
    }
}

  1. PlayFab 프로젝트 설정으로 이동합니다.
  2. 클라우드 스크립트 파일을 업로드합니다.
  3. 클라우드 스크립트를 프로덕션 환경에서 실행합니다.
  4. 클라이언트 측 논리를 애플리케이션에서 함수 호출에 추가합니다. GetXsollaLoginToken을 함수 이름으로 지정합니다. 매개 변수 전달은 하지 않아도 됩니다.

사용자 JWT 수신 함수 호출의 예시

Copy
Full screen
Small screen
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를 추가하지 않고 자체적으로 하실 수 있습니다.

  1. 애플리케이션에서 API를 이용해 자체적으로 작업하거나 엑솔라 SDK를 이용해 작업할 메서드를 구현합니다.

이 기사가 도움이 되었나요?
감사합니다!
개선해야 할 점이 있을까요? 메시지
유감입니다
이 기사가 도움이 안 된 이유를 설명해 주세요. 메시지
의견을 보내 주셔서 감사드립니다!
메시지를 검토한 후 사용자 경험 향상에 사용하겠습니다.
이 페이지 평가
이 페이지 평가
개선해야 할 점이 있을까요?

답하기 원하지 않습니다

의견을 보내 주셔서 감사드립니다!

유용한 링크

마지막 업데이트: 2022년 10월 21일

오자 또는 기타 텍스트 오류를 찾으셨나요? 텍스트를 선택하고 컨트롤+엔터를 누르세요.

문제 보고
콘텐츠를 항상 검토합니다. 여러분의 피드백은 콘텐츠를 개선에 도움이 됩니다.
후속 조치를 위해 이메일을 제공해 주세요
의견을 보내 주셔서 감사드립니다!