# UI 拡張機能で役割を使用する

UI 拡張機能にユーザーの役割を組み込んで、さまざまな役割に合わせて機能を調整する方法をご紹介します。

Stripe Apps の UI 拡張機能を使用して、ダッシュボードで有効なユーザーの役割を読み取ることができます。アプリでは、ユーザーの個々の役割に対してさまざまな機能を公開できます。

UI 拡張機能 SDK は、アプリのエンドユーザーに関する有用な情報を提供します。`userContext` オブジェクトの `roles` フィールドには、有効なユーザーの役割のリストが示されます。ユーザーのコンテキストで役割を使用し、ユーザーの役割に基づいてアプリのコンテンツを調整できます。

ロールに加えて、`appContext.authorizedPermissions` を使用して、アプリが現在のコンテキストに対して持つ権限を確認できます。フィールドの完全なリストについては、[UI Extension SDK API](https://docs.stripe.com/stripe-apps/reference/extensions-sdk-api.md) の `appContext` を参照してください。

## ダッシュボードに関するユーザーの役割を決定する方法

拡張機能には、有効なダッシュボードユーザーに関する情報が設定される `userContext` プロパティがあります。このオブジェクトには、有効なユーザーに割り当てられた役割ごとの `RoleDefinition` オブジェクトの配列である `roles` フィールドがあります。

役割の定義には以下のフィールドがあります。

| フィールド名 | タイプ | 例 | **Description** |
| --- | --- | --- | --- |
| タイプ | ‘builtIn’ | ‘custom’ | builtIn | 役割の種類を指定します。カスタム役割は[プライベートアプリ](https://docs.stripe.com/stripe-apps/distribution-options.md#share-with-team-members)にのみ使用できます。 |
| id | 文字列 | 開発者 | ユーザーの役割を表す、安定した機械可読の識別子です。`name` とは異なり、役割の表示名が更新されても変更されないため、比較用途に使用しても安全です。 |
| 名前 | 文字列 | 開発者 | ユーザーの役割を表すわかりやすい名称です。プログラムによる比較には `id` を使用してください。`name` は変更される可能性があります。 |

`id` フィールドは、ユーザーの役割を表す安定した識別子を提供し、UI 拡張機能の機能変更に使用できます。役割の表示名が変更された場合の問題を防ぐため、プログラムでの役割比較には `name` ではなく `id` を使用してください。

## 組み込みの役割

Stripe では、すべてのアカウントで利用可能な一連の組み込みの役割が提供されています。これらの役割は、公開アプリとプライベートアプリの両方で使用できます。組み込みの役割の完全なリストと、それぞれの役割で実行可能な操作については、[ユーザーの役割](https://docs.stripe.com/get-started/account/teams/roles.md)を確認してください。

## カスタムユーザーの役割 (プライベートアプリのみ)

カスタムの役割は、アカウント管理者が Stripe ダッシュボードの **設定** > **チームとセキュリティ** から作成する、アカウント固有の役割です。カスタムの役割は特定のアカウントに限定されるため、[プライベートアプリ](https://docs.stripe.com/stripe-apps/distribution-options.md#share-with-team-members)でのみ使用できます。アプリ開発者がカスタムの役割を作成または定義することはできません。アプリでカスタムの役割を使用する場合は、アカウント管理者と連携し、作成するカスタムの役割と ID について調整してください。

カスタムの役割がアプリに公開されると、その `id` は `role_` プレフィックスが削除された役割のトークンになります。たとえば、トークンが `role_abc123` のカスタムの役割は、`userContext.roles` で `{ id: 'abc123', type: 'custom', name: 'Shipping Manager' }` として表示されます。

カスタムの役割が公開アプリに公開されることはありません。アプリが一般公開されている場合、`userContext.roles` には組み込みの役割のみが含まれます。

## ダッシュボードでの役割に基づいてコンテンツを調整する

この情報は一般的に、ユーザーの役割に基づいてコンテンツを条件付きで表示するために使用します。以下のアプリは、特定のユーザーの役割に合わせてコンテンツを表示するサンプルアプリです。

```tsx
import { Badge, Box, Inline, ContextView } from "@stripe/ui-extension-sdk/ui";
import type { ExtensionContextValue } from "@stripe/ui-extension-sdk/context";

const App = ({ userContext }: ExtensionContextValue) => {
  // Use `id` for stable role comparisons instead of `name`
  const isAdmin = userContext?.roles?.some(role => role.id === 'admin');
  const isDeveloper = !isAdmin && userContext?.roles?.some(role => role.id === 'developer');
  const isAnotherRole = !isDeveloper && !isAdmin;

  return (
    <ContextView
      title="Role based access"
    >
      <Box>
        <Box css={{ paddingBottom: 'large'}}>Active user roles: {userContext?.roles?.map(role => <Badge key={role.id}>{role.name}</Badge>)}</Box>

        { isAdmin && (<Box>Only <Inline css={{ fontWeight: 'semibold' }}>admin</Inline> users can see this message.</Box>) }
        { isDeveloper && (<Box>Only <Inline css={{ fontWeight: 'semibold' }}>developers</Inline> can see this message.</Box>) }
        { isAnotherRole && (<Box>Only users who are not admins or developers can see this message.</Box>) }
      </Box>
    </ContextView>
  );
};

export default App;
```
![管理者ユーザーに関する上記のサンプルコードの結果を示すスクリーンショット](https://b.stripecdn.com/docs-statics-srv/assets/roles-example.7fb1048ac4656aee8a39a33d9179ad26.png)

管理者ユーザーとしてアプリを表示する場合のサンプルアプリの結果

## ダッシュボードの役割に基づいてアクセスを制限する

役割の確認機能を使用して、ビュー全体を特定の役割に制限します。これは、フルページアプリや、特定のチームメンバーのみがアクセスできるビューで役立ちます。

役割に基づく確認は UI にのみ適用されます。ユーザーに表示される内容は制御されますが、API を介して実行できる操作は制御されません。ユーザーの役割に関係なく、アプリのサンドボックスは読み込まれます。アプリがバックエンド API コールを行う場合は、サーバー側でも役割の制限を適用してください。

次の例では、必要な役割を持たないユーザーに対してブロック状態を表示します。

```tsx
import { ContextView, Box } from "@stripe/ui-extension-sdk/ui";
import type { ExtensionContextValue } from "@stripe/ui-extension-sdk/context";

const App = ({ userContext }: ExtensionContextValue) => {
  const hasAccess = userContext?.roles?.some(role => role.id === 'admin');

  if (!hasAccess) {
    return (
      <ContextView title="Access restricted">
        <Box>You need the Administrator role to access this feature.</Box>
      </ContextView>
    );
  }

  return (
    <ContextView title="Admin panel">
      {/* content for admins only */}
    </ContextView>
  );
};

export default App;
```

それぞれに役割の保護が必要な複数のビューを持つアプリの場合は、確認の重複を避けるために共有ラッパーコンポーネントを作成します。

```tsx
import type { ExtensionContextValue } from "@stripe/ui-extension-sdk/context";
import { ContextView, Box } from "@stripe/ui-extension-sdk/ui";

type RoleGateProps = {
  userContext: ExtensionContextValue["userContext"];
  allowedRoles: string[];
  children: React.ReactNode;
};

const RoleGate = ({ userContext, allowedRoles, children }: RoleGateProps) => {
  const hasAccess = userContext?.roles?.some(role =>
    role.id !== undefined && allowedRoles.includes(role.id)
  );

  if (!hasAccess) {
    return (
      <ContextView title="Access restricted">
        <Box>You don't have permission to use this feature.</Box>
      </ContextView>
    );
  }

  return <>{children}</>;
};
```

役割ベースのアクセスを実装する際は、次の点に注意してください。

- 組み込みアプリなどの一部のコンテキストでは、`userContext.roles` が `undefined` になる場合があります。読み取る際は、常にオプショナルチェイニングを使用してください。
- マニフェストレベルでの役割制限のサポートはありません。`stripe-app.json` には `allowed_roles` フィールドは存在しません。保護が必要なすべてのビューで、コンポーネントコード内に確認を実装する必要があります。
- 公開アプリの場合、使用できるのは組み込みの役割 ID のみです。公開アプリではカスタムの役割が暗黙的に除外されるため、`userContext.roles` に表示されることはありません。

## See also

- [UI を構築する](https://docs.stripe.com/stripe-apps/build-ui.md)
- [UI Extension SDK API リファレンス](https://docs.stripe.com/stripe-apps/reference/extensions-sdk-api.md)
- [ユーザーの役割](https://docs.stripe.com/get-started/account/teams/roles.md)
- [配信オプション](https://docs.stripe.com/stripe-apps/distribution-options.md)
