7
@m_okubo

MetaMaskによるログイン機能の実装

はじめに

DAppsの開発を始めて最初に悩むのが「ログイン機能をどう実装するか?」だと思います。
DAppsであるからには、ログインIDはウォレットのアドレスであるべきだと考えるのが自然でしょう。
ですが、ウォレットのアドレスは人間が覚えておくようには設計されていません。
では、DAppsのログイン機能はどう実装するべきなのでしょうか?
ここでは、その問題に対する解決策の一つとして、ウォレットの一種であるMetaMaskと連携したログイン機能の実装例を紹介したいと思います。

※MetaMaskは数あるウォレットの中でもリスクの大きいウォレットに分類されます。
ユーザーの中には大事なウォレットアドレスをMetaMaskと紐付けることに抵抗感を覚える人もいるということを踏まえた上で採用を検討してください。

MetaMask: web3 will be deprecated?

現在、MetaMaskとの連携でよく紹介されているのが「web3」オブジェクトを利用した方法です。
ですが、この方法は将来的に廃止されることが決まっており、既にGoogle Chromeでは「deprecated(非推奨)」となっています。
そのため、ここでは「web3」オブジェクトの代わりに「ethereum」オブジェクトを利用して実装してみたいと思います。
(ちなみに「ethereum」オブジェクトは「web3.currentProvider」と等価です。)

ethereumによるログイン機能の実装

ここでは以下のサイトを参考にログイン機能を実装していきます。

Ethereum Provider API - MetaMask Docs
https://docs.metamask.io/guide/ethereum-provider.html

「ethereum」オブジェクトはGoogle Chrome拡張であるMetaMaskによってDAppsに注入されますので、Google Chromeブラウザを使用してMetaMaskをインストールしていることが大前提になります。
そのため、最初の分岐条件は以下のようになります。

if (!window.ethereum || !window.ethereum.isMetaMask) {
  alert('MetaMaskをインストールしてください。')
  return
}

「ethereum.isMetaMask」がMetaMaskをインストールしているかを表すプロパティなのですが、MetaMaskをインストールしていないと、そもそもethereumオブジェクトが注入されないので、ここではethereumオブジェクトの存在チェックも行っています。
MetaMaskがインストールされていたら、次はログイン状態を確認します。

window.ethereum.request({method: 'eth_accounts'}).then(accounts => {
  if (accounts.length > 0) {
    // ログイン済み
  } else {
    // 未ログイン
  }
})

複数アカウントに同時にログインしている場合があるのか謎ですが、確認方法としてはログイン中のアカウント一覧を取得して一覧の件数が1件以上であればログインしていると判定します。

ログイン済みの場合

接続中のネットワークの種類を確認します。ネットワークの種類が異なる場合はネットワークの切り替えを促します。
また、ネットワークの種類が一致する場合はログイン中のアカウント一覧の最初の要素をログインIDとします。

if (window.ethereum.chainId != 0x1) {
  alert('メインネットに切り替えてください。')
} else {
  this.loginId = accounts[0]
}

尚、ネットワークの種類は以下の通りです。

ネットワークの種類
0x1 メインネット
0x3 Ropstenテストネット
0x4 Rinkebyテストネット
0x5 Goerliテストネット
0x2a Kovanテストネット

未ログインの場合

ログインを促すダイアログを表示します。

MetaMask Login

window.ethereum.request({method: 'eth_requestAccounts'}).then(requestAccounts => {
  if (requestAccounts.length > 0) {
    if (window.ethereum.chainId != 0x1) {
      alert('メインネットに切り替えてください。')
    } else {
      window.location.reload()
    }
  } else {
    alert('MetaMaskにログインしてください。')
  }
})

ethereum.requestメソッドの戻り値はPromiseオブジェクトのため、ユーザーがMetaMaskにログインするとthen以降の処理が実行されます。
無事にログインが成功した場合、通常のWebアプリケーションであればログイン画面からメイン画面への遷移が発生しますが、MetaMaskでログインした場合は、画面を再読み込みするのが良いでしょう。

ログアウト機能の実装

ここまででログイン機能については実装できましたので、次にログアウト機能を実装します。
ログアウトはアカウント情報の変更イベントをリッスンすることで実装することができます。

window.ethereum.on('accountsChanged', changedAccounts => {
  if (changedAccounts.length == 0) {
    // ログアウト
    window.location.reload()
  } else {
    // アカウント変更
  }
})

ここではログイン中のアカウント一覧が0件になった(=ログアウトした)場合のみ、画面を再読み込みしていますが、DAppsによってはアカウントが変更になった場合も、画面を再読み込みすることによって「ログアウト→別アカウントでログイン」を実現できると思います。
また、DAppsによってはネットワークの種類が変更された場合もログアウトと判定する必要がありますが、これも先ほどと同じ要領で実装できます。

window.ethereum.on('chainChanged', changedChainId => {
  if (changedChainId != 0x1) {
    window.location.reload()
  }
})

これでMetaMaskと連携したログイン/ログアウトの機能が実装できました。
最初にも少し触れた通り、「ethereum」オブジェクトは「web3.currentProvider」と等価ですので、ログイン機能だけではなく、イーサリアムや独自トークンの送金等も可能です。
この記事が少しでも皆さんのDApps開発のお役に立てれば幸いです。

最後に

モバイル版MetaMaskの正式リリースが待ち遠しい~!!

7
ユーザー登録して、Qiitaをもっと便利に使ってみませんか。
  1. あなたにマッチした記事をお届けします
    ユーザーやタグをフォローすることで、あなたが興味を持つ技術分野の情報をまとめてキャッチアップできます
  2. 便利な情報をあとで効率的に読み返せます
    気に入った記事を「ストック」することで、あとからすぐに検索できます

コメント

この記事にコメントはありません。
あなたもコメントしてみませんか :)
ユーザー登録
すでにアカウントを持っている方はログイン
記事投稿イベント開催中
競技プログラミング研究月間 - みんなでさらなる高みを目指そう
~
Microsoft Buildで発表された技術情報に関する記事を投稿しよう!
~