Identity によるアクセスコントロールの追加
Dapps では、ユーザーごとに異なる操作を制御するために、ロールベースのパーミッションが必要になることがあります。
このチュートリアルでは、ユーザー Identity の作成と切り替えを説明するために、異なるロールに割り当てられたユーザーに対して異なる挨拶文を表示するシンプルな Dapp を作成します。
この例では、owner、admin、authorized の3つのロールが指定されています。
- adminロールが割り当てられているユーザーには、- You have a role with administrative privilegesという挨拶文が表示されます。
- Authorizedロールが割り当てられているユーザーには、- Would you like to play a game?という挨拶文が表示されます。
- これらのロールが割り当てられていないユーザーには、 - Nice to meet you!という挨拶文が表示されます。
さらに、Canister を初期化したユーザー Identity にのみ owner ロールが割り当てられ、 owner と admin ロールのみが他のユーザーにロールを割り当てることができます。
大まかにいうと、各ユーザーは公開鍵と秘密鍵のペアを持ちます。ユーザーがアクセスする Canister ID に紐付いた公開鍵がセキュリティ Principal となり、これをメッセージ呼び出し元として使用して、Internet Computer ブロックチェーン上で動作する Canister への関数コールを認証することができます。次の図は、ユーザー Identity がメッセージ呼び出し元を認証する方法を簡略化して示しています。
始める前に
チュートリアルを始める前に、以下を確認してください:
- ダウンロードとインストール で説明されているように、SDK パッケージをダウンロードしインストールする。 
- デフォルトのユーザー Identity が作成されるようなコマンドを少なくとも 1 つ実行する。デフォルトのユーザー Identity は、すべてのプロジェクトのために - $HOME/.config/dfx/identity/ディレクトリにグローバルに保存されます。
- Visual Studio Code を IDE として使用している場合、言語エディタプラグインのインストール にあるように、Motoko 用の Visual Studio Code プラグインをインストールする。 
- コンピュータ上で動作しているローカル Canister 実行環境プロセスを停止する。 
新しいプロジェクトを作成する
アクセスコントロールとユーザー Identity の切り替えをテストするために、新しいプロジェクトディレクトリを作成します:
- ローカルコンピューターでターミナルシェルを開きます(まだ開いていない場合)。 
- Internet Computer ブロックチェーンのプロジェクト用に使用しているフォルダがある場合にはそちらに移動します。 
- 以下のコマンドを実行し、新しいプロジェクトを作成します: - dfx new access_hello
- 次のコマンドを実行して、プロジェクトディレクトリに移動します: - cd access_hello
デフォルトの Dapp を変更する
このチュートリアルでは、テンプレートのソースコード・ファイルを、ロールの割り当てと取得のための機能を持つ Dapp に置き換えます。
デフォルトの Dapp を変更するには、次のようにします:
- src/access_hello/main.moファイルをテキストエディタで開き、既存のコンテンツを削除します。
- このコードをコピーして、ファイルに貼り付けます。 - この Dapp の主要な要素をいくつか見てみましょう: - これまでのチュートリアルで見てきた - greet関数のバリエーションであることに気がつくかもしれません。- しかし、このアプリでは、 - greet関数がメッセージの呼び出し元を利用して、適用すべきパーミッションを決定し、呼び出し元に関連するパーミッションに基づいて、どの挨拶文を表示すべきかを決定します。
- 1つは - Roles用、もう1つは- Permissions用のカスタムタイプです。
- assign_role関数を使用すると、メッセージの呼び出し元が Identity に関連付けられた Principal にロールを割り当てることができます。
- callerPrincipal関数を使用すると、Identity に関連付けられた Principal を返せるようになります。
- my_role関数を使用すると、Identity に関連付けられたロールを返すことができます。
 
- 変更を保存して、 - main.moファイルを閉じてください。
ローカル Canister の実行環境を起動する
access_hello プロジェクトをビルドする前に、開発環境で動作しているローカル Canister 実行環境、または Internet Computer のブロックチェーンメインネットに接続する必要があります。
ローカル Canister 実行環境を起動するには:
- ローカルコンピューターで新しいターミナルウィンドウまたはタブを開きます。 
- 必要に応じて、プロジェクトのルートディレクトリに移動します。 
- コンピューター上で以下のコマンドを実行し、ローカルの Canister 実行環境を起動します: - dfx start --background- ローカル Canister の実行環境が起動操作を完了したら、次のステップに進みます。 
Dapp の登録、ビルド、デプロイ
開発環境で動作しているローカル Canister 実行環境に接続したら、dfx deploy コマンドを実行して、一度にアプリの登録、ビルド、およびデプロイを行うことができます。また、dfx canister create、 dfx build と dfx canister install コマンドでこれらの手順を個別に行うことが可能です。
Dapp をローカルにデプロイするには:
- 必要に応じて、まだプロジェクトのルートディレクトリにいることを確認します。 
- 以下のコマンドを実行して、 - access_helloバックエンド Dapp を登録、ビルド、デプロイします:- dfx deploy access_hello
 Creating a wallet canister on the local network.
 The wallet canister on the "local" network for user "default" is "rwlgt-iiaaa-aaaaa-aaaaa-cai"
 Deploying: access_hello
 Creating canisters...
 Creating canister "access_hello"...
 "access_hello" canister created with canister id: "rrkah-fqaaa-aaaaa-aaaaq-cai"
 Building canisters...
 Installing canisters...
 Installing code for canister access_hello, with canister_id rrkah-fqaaa-aaaaa-aaaaq-cai
 Deployed canisters.
現在の Identity コンテキストを確認する
追加の Identity を作成する前に、default Identity に関連する Principal 識別子と default Identity の Cycle ウォレットを確認しましょう。Internet Computer ブロックチェーンでは、 Principal はユーザー、Canister、ノード、サブネットを識別するための内部的な代表値です。 Principal のテキスト表現は、 Principal データタイプで作業しているときに表示される外部識別子です。
現在の Identity と Principal を確認するには:
- 以下のコマンドを実行し、現在アクティブな Identity を確認します: - dfx identity whoami- このコマンドは、次のような出力を表示します: - default
- 以下のコマンドを実行して、 - defaultユーザー Identity の Principal を確認します:- dfx identity get-principal- このコマンドは、次のような出力を表示します: - zen7w-sjxmx-jcslx-ey4hf-rfxdq-l4soz-7ie3o-hti3o-nyoma-nrkwa-cqe
- 以下のコマンドを実行して、 - defaultユーザー Identity に関連するロールを確認します:- dfx canister --wallet=$(dfx identity get-wallet) call access_hello my_role- このコマンドは、次のような出力を表示します: - (opt variant { owner })
新しいユーザー Identity を作成する
Dapp のアクセスコントロールのテストを始めるために、いくつかの新しいユーザー Identity を作成し、それらのユーザーに異なるロールを割り当ててみましょう。
新しいユーザー Identity を作成するには、次のようにします:
- 必要であれば、プロジェクトディレクトリに留まっていることを確認します。 
- 以下のコマンドを実行して、新しい管理者ユーザー Identity を作成します: - dfx identity new ic_admin- このコマンドは、次のような出力を表示します: - Creating identity: "ic_admin".
 Created identity: "ic_admin".
- 新しいユーザー Identity がどのロールにも割り当てられていないことを確認するために、 - my_role関数を呼び出してください。- dfx --identity ic_admin canister call access_hello my_role- このコマンドは、次のような出力を表示します: - Creating a wallet canister on the local network.
 The wallet canister on the "local" network for user "ic_admin" is "ryjl3-tyaaa-aaaaa-aaaba-cai"
 (null)
- 次のコマンドを実行して、現在アクティブな Identity コンテキストを新しい - ic_adminユーザー Identity を使用するように切り替え、- ic_adminユーザーに関連付けられた Principal を表示します:- dfx identity use ic_admin && dfx identity get-principal- このコマンドは、次のような出力を表示します: - Using identity: "ic_admin".
 c5wa6-3irl7-tuxuo-4vtyw-xsnhw-rv2a6-vcmdz-bzkca-vejmd-327zo-wae
- 以下のコマンドを実行して、 - access_helloCanister の呼び出しに使用された Principal を確認します:- dfx canister call access_hello callerPrincipal- このコマンドは、次のような出力を表示します: - (principal "ryjl3-tyaaa-aaaaa-aaaba-cai")- デフォルトでは、 - access_helloCanister のメソッドを呼び出すために使用される Principal は、Cycle ウォレットの識別子になります。しかし、アクセスコントロールを説明するために、Cycle ウォレットではなく、ユーザーコンテキストに関連付けられた Principal を使用したいと思います。しかし、その前に- ic_adminユーザーにロールを割り当ててみましょう。そのためには、- ownerロールを持つ- defaultユーザー Identity に切り替える必要があります。
Identity にロールを割り当てる
IC_admin の Identity に admin ロールを割り当てるには:
- 次のコマンドを実行して、現在アクティブな Identity コンテキストを切り替えて、 - defaultユーザ Identity を使用するようにします:- dfx identity use default
- IC_adminPrincipal に- adminロールを割り当てるには、Candid 構文で次のようなコマンドを実行します:- dfx canister --wallet=$(dfx identity get-wallet) call access_hello assign_role '((principal "c5wa6-3irl7-tuxuo-4vtyw-xsnhw-rv2a6-vcmdz-bzkca-vejmd-327zo-wae"),opt variant{admin})'
Principal ハッシュは、 ic_admin Identity に対して dfx identity get-principal コマンドで返されたものに置き換える必要があります。
+ オプションで、コマンドを再実行して my_role 関数を呼び出し、ロールの割り当てを確認することができます。
+
dfx --identity ic_admin canister call access_hello my_role
+ このコマンドは、次のような出力を表示します:
+
(opt variant { admin })
- 先ほど - adminロールを割り当てた- ic_adminユーザーの Identity を使用して、以下のコマンドを実行して- greet関数を呼び出してください:- dfx --identity ic_admin canister call access_hello greet "Internet Computer Admin"- このコマンドは、次のような出力を表示します: - (
 "Hello, Internet Computer Admin. You have a role with administrative privileges.",
 )
オーソライズされたユーザー Identity の追加
この時点では、owner ロールを持つ default ユーザー Identity と admin ロールを持つ ic_admin ユーザー Identity が存在しています。もうひとつのユーザー Identity を追加して、authorized ロールに割り当ててみましょう。ただし、この例では、ユーザーの Principal を保存するために環境変数を使用します。
新しいオーソライズされたユーザー Identity を追加するには、次のようにします:
- 必要であれば、プロジェクトディレクトリに留まっていることを確認します。 
- 次のコマンドを実行して、新しい正規ユーザー Identity を作成します: - dfx identity new alice_auth- このコマンドは、次のような出力を表示します: - Creating identity: "alice_auth".
 Created identity: "alice_auth".
- 以下のコマンドを実行して、現在アクティブな Identity コンテキストを切り替えて、新しい - alice_authユーザー Identity を使用するようにします:- dfx identity use alice_auth
- 以下のコマンドを実行して、 - alice_authユーザーの Principal を環境変数に格納します:- ALICE_ID=$(dfx identity get-principal)- 以下のコマンドを実行することで、保存されている Principal を確認することができます: - echo $ALICE_ID- このコマンドは、次のような出力を表示します: - b5quc-npdph-l6qp4-kur4u-oxljq-7uddl-vfdo6-x2uo5-6y4a6-4pt6v-7qe
- ic_adminの Identity を使用して、以下のコマンドを実行して- alice_authに- authorizedロールを割り当ててください:- dfx --identity ic_admin canister call access_hello assign_role "(principal \"$ALICE_ID\", opt variant{authorized})"
- ロールの割り当てを確認するために - my_role関数を呼び出します。- dfx --identity alice_auth canister call access_hello my_role- このコマンドは、次のような出力を表示します: - (opt variant { authorized })
- 先ほど - authorizedロールを割り当てた- alice_authユーザーの Identity を使用して、以下のコマンドを実行して- greet関数を呼び出してください:- dfx canister call access_hello greet "Alice"- このコマンドは、次のような出力を表示します: - (
 "Welcome, Alice. You have an authorized account. Would you like to play a game?",
 )
未承認のユーザー Identity を追加する
ここまでで、特定のロールと権限を持つユーザーを作成する簡単な例を見ました。次のステップでは、ロールが割り当てられていない、あるいは特別なパーミッションが与えられていないユーザー Identity を作成します。
未承認のユーザー Identity を追加するには、以下の手順に従います:
- 必要であれば、プロジェクトディレクトリに留まっていることを確認します。 
- 必要に応じて、以下のコマンドを実行して、現在アクティブな Identity を確認します。 - dfx identity whoami
- 以下のコマンドを実行して、新しいユーザーIdentity を作成します: - dfx identity new bob_standard- このコマンドは、次のような出力を表示します: - Creating identity: "bob_standard".
 Created identity: "bob_standard".
- 以下のコマンドを実行して、 - bob_standardユーザの Principal を環境変数に格納します:- BOB_ID=$(dfx --identity bob_standard identity get-principal)
- ロールを割り当てるために - bob_standardIdentity を使用しようとしてみてください。- dfx --identity bob_standard canister call access_hello assign_role "(principal \"$BOB_ID\", opt variant{authorized})"- のコマンドは - unauthorizedエラーを返します。
- 以下のコマンドを実行して、 - defaultユーザー Identity を使用して- bob_standardに- ownerロールを割り当ててみてください。- dfx --identity default canister --wallet=$(dfx --identity default identity get-wallet) call access_hello assign_role "(principal \"$BOB_ID\", opt variant{owner})"- このコマンドは、ユーザーに - ownerロールを割り当てることができないため失敗します。
- 次のコマンドを実行して、 - bob_standardユーザー Identity を使用して- greet関数を呼び出します:- dfx --identity bob_standard canister call access_hello greet "Bob"- このコマンドは、次のような出力を表示します: - ("Greetings, Bob. Nice to meet you!")
複数のコマンドでユーザー Identity を設定する
これまで、個々のコマンドでユーザー Identity を作成し、切り替える方法について見てきました。また、使用したいユーザー Identity を指定し、そのユーザー Identity のコンテキストで複数のコマンドを実行することもできます。
1つのユーザー Identity で複数のコマンドを実行するには:
- 必要であれば、プロジェクトディレクトリに留まっていることを確認します。 
- 以下のコマンドを実行して、現在利用可能なユーザー Identity を一覧表示します: - dfx identity list- のコマンドは、現在アクティブなユーザー Identity を示すアスタリスクとともに、次のような出力を表示します。 - alice_auth
 bob_standard
 default *
 ic_admin- この例では、明示的に別のIdentity を選択しない限り、 - defaultのユーザー Identity が使用されます。
- リストから新しいユーザー Identity を選択し、次のようなコマンドを実行して、それをアクティブユーザーコンテキストにします: - dfx identity use ic_admin- + このコマンドは、次のような出力を表示します: - Using identity: "ic_admin".- dfx identity listコマンドを再実行すると、- ic_adminユーザー Identity は現在アクティブなユーザコンテキストであることを示すためにアスタリスクを表示します。- コマンドラインで - --identityを指定しなくても、選択したユーザーIdentity を使用してコマンドを実行できるようになりました。
ローカル Canister の実行環境を停止する
Dapp のテストや Identity の利用が終わったら、ローカル Canister 実行環境を停止して、バックグラウンドで実行し続けないようにします。
ローカル Canister の実行環境を停止するには、以下の手順で行います:
- ネットワーク操作が表示されているターミナルで、Control-C キーを押して、ローカルネットワークの処理を中断します。 
- 以下のコマンドを実行して、ローカル Canister の実行環境を停止します: - dfx stop
もっと学ぶには?
Indentity と認証についてより詳しい情報をお求めの方は、以下の関連資料をご覧ください: