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_hello
Canister の呼び出しに使用された Principal を確認します:dfx canister call access_hello callerPrincipal
このコマンドは、次のような出力を表示します:
(principal "ryjl3-tyaaa-aaaaa-aaaba-cai")
デフォルトでは、
access_hello
Canister のメソッドを呼び出すために使用される Principal は、Cycle ウォレットの識別子になります。しかし、アクセスコントロールを説明するために、Cycle ウォレットではなく、ユーザーコンテキストに関連付けられた Principal を使用したいと思います。しかし、その前にic_admin
ユーザーにロールを割り当ててみましょう。そのためには、owner
ロールを持つdefault
ユーザー Identity に切り替える必要があります。
Identity にロールを割り当てる
IC_admin の Identity に admin ロールを割り当てるには:
次のコマンドを実行して、現在アクティブな Identity コンテキストを切り替えて、
default
ユーザ Identity を使用するようにします:dfx identity use default
IC_admin
Principal に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_standard
Identity を使用しようとしてみてください。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 と認証についてより詳しい情報をお求めの方は、以下の関連資料をご覧ください: