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

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

Last updated on February 4, 2026

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

概要

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

前提条件

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

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

ユーザー所有権検証の実装

例として、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."));

// 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
{
//ギルドIDで指定されたギルドデータが存在するかどうかを確認
var guildData = _ABProvider.Sdk.Cloudsave.AdminGameRecord.AdminGetGameRecordHandlerV1Op
.Execute<GuildProgressData>(gpKey, request.Namespace);
if (guildData == null)
throw new Exception("NULL response from cloudsave service.");

//存在する場合、所有者ユーザーIDを確認
if (guildData.Value != null)
{
if (guildData.Value.OwnerId != loginUserId)
throw new Exception("You don't have access to this data.");
}

//ギルドデータが存在し、ログインユーザーに属している。更新を続行
}
catch (HttpResponseException hrx)
{
if (hrx.StatusCode != HttpStatusCode.NotFound)
throw;

//ギルドデータが存在しない。作成を続行
}

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.");

//存在する場合、所有者ユーザー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リクエスト処理の詳細については、こちらをご覧ください。