メインコンテンツまでスキップ

Extend Service Extensionでユーザー所有権検証を実装する

Last updated on July 14, 2026

注釈:本資料はAI技術を用いて翻訳されています。

Overview

デフォルトでは、Extend Service Extensionのアプリテンプレートには基本的なユーザー検証メカニズムのみが含まれています。 ただし、特定のデータセットに対してユーザー検証が必要な場合は、コードをカスタマイズすることで簡単に実装できます。

Prerequisites

Extend Service Extensionのアプリテンプレートをクローンしていること。

git clone https://github.com/AccelByte/extend-service-extension-csharp

Implement user ownership validation

例として、Extend Service Extensionのアプリテンプレートを拡張して、各ギルドデータに所有権情報を組み込むことができます。 ギルドデータの作成時に、現在認証されているユーザーIDを所有者IDとして割り当て、この情報をギルドデータと共に保存します。 その後、ユーザーがギルドデータにアクセスしようとすると、ユーザーIDを検証し、保存された所有者IDと一致しない場合はアクセスを拒否します。

注記

このメカニズムは、ユーザーアクセストークンのペイロード内のsubフィールドに格納されたユーザーIDを利用します。OAuthクライアントのアクセストークンにはsubフィールドが含まれないため、クライアントクレデンシャルを使用する場合は所有権情報が保存されません。

  1. Model/GuildProgressData.csNamespaceプロパティの下にOwnerIdプロパティを追加します。
...

[JsonPropertyName("owner_id")]
public string OwnerId { get; set; } = "";

...
  1. Classes/AuthorizationInterceptor.csで、アクセストークンのペイロードからユーザーIDをgRPCコンテキストのUserStateに追加します。
...

qPermission = (new Regex(@"\{(namespace|NAMESPACE)\}")).Replace(qPermission, (m) => _ABProvider.Sdk.Namespace);
int actNum = (int)qAction;
bool b = _ABProvider.Sdk.ValidateToken(authParts[1], qPermission, actNum);
if (!b)
throw new RpcException(new Status(StatusCode.PermissionDenied, $"Permission {qPermission} [{qAction}] is required."));

// Add these code below after ValidateToken
var tokenPayload = _ABProvider.Sdk.ParseAccessToken(authParts[1], false);
if (tokenPayload == null)
throw new RpcException(new Status(StatusCode.Unauthenticated, $"Invalid access token payload."));

string userId = "";
if (tokenPayload.Sub != null)
userId = tokenPayload.Sub;

context.UserState.Add("loginUserId", userId);

...
  1. Service/MyService.csファイル内のCreateOrUpdateGuildProgressの実装を変更します。
public override Task<CreateOrUpdateGuildProgressResponse> CreateOrUpdateGuildProgress(CreateOrUpdateGuildProgressRequest request, ServerCallContext context)
{
string actualGuildId = request.GuildProgress.GuildId.Trim();
if (actualGuildId == "")
actualGuildId = Guid.NewGuid().ToString().Replace("-", "");

string gpKey = $"guildProgress_{actualGuildId}";

string loginUserId = "";
if (context.UserState.TryGetValue("loginUserId", out object? tempValue))
{
if (tempValue != null)
loginUserId = tempValue.ToString()!;
}
else
throw new Exception("No login user id data in context.");

try
{
//check whether guild data specified by guild is exists or not
var guildData = _ABProvider.Sdk.Cloudsave.AdminGameRecord.AdminGetGameRecordHandlerV1Op
.Execute<GuildProgressData>(gpKey, request.Namespace);
if (guildData == null)
throw new Exception("NULL response from cloudsave service.");

//if it exists, check owner user id.
if (guildData.Value != null)
{
if (guildData.Value.OwnerId != loginUserId)
throw new Exception("You don't have access to this data.");
}

//Guild data exists and belong to login user. Proceed to update
}
catch (HttpResponseException hrx)
{
if (hrx.StatusCode != HttpStatusCode.NotFound)
throw;

//Guild data does not exists. Proceed to create.
}

var gpValue = GuildProgressData.FromGuildProgressGrpcData(request.GuildProgress);
gpValue.GuildId = actualGuildId;
gpValue.OwnerId = loginUserId;

var response = _ABProvider.Sdk.Cloudsave.AdminGameRecord.AdminPostGameRecordHandlerV1Op
.Execute<GuildProgressData>(gpValue, gpKey, request.Namespace);
if (response == null)
throw new Exception("NULL response from cloudsave service.");

GuildProgressData savedData = response.Value!;

return Task.FromResult(new CreateOrUpdateGuildProgressResponse()
{
GuildProgress = savedData.ToGuildProgressGrpcData()
});
}
  1. Service/MyService.csファイル内のGetGuildProgressの実装を変更します。
public override Task<GetGuildProgressResponse> GetGuildProgress(GetGuildProgressRequest request, ServerCallContext context)
{
string gpKey = $"guildProgress_{request.GuildId.Trim()}";

string loginUserId = "";
if (context.UserState.TryGetValue("loginUserId", out object? tempValue))
{
if (tempValue != null)
loginUserId = tempValue.ToString()!;
}
else
throw new Exception("No login user id data in context.");

var response = _ABProvider.Sdk.Cloudsave.AdminGameRecord.AdminGetGameRecordHandlerV1Op
.Execute<GuildProgressData>(gpKey, request.Namespace);
if (response == null)
throw new Exception("NULL response from cloudsave service.");

//if it exists, check owner user id.
if (response.Value != null)
{
if (response.Value.OwnerId != loginUserId)
throw new Exception("You don't have access to this data.");
}

GuildProgressData savedData = response.Value!;
return Task.FromResult(new GetGuildProgressResponse()
{
GuildProgress = savedData.ToGuildProgressGrpcData()
});
}
備考

gRPCリクエスト処理の詳細については、こちらを参照してください。