社内で利用しようとしてるとあるMicrosoftの製品。しかし、現場に浸透せずこのままでは朽ちていくだけ。殆どの企業で言える事なのだけれど、入れる事がゴールになっていて、現場の利用者のフォローや研修、また利用がしやすい(またはそうなるような動機づけとなるもの)を一切やらないとこうなるという典型例です。

しかし、使え!!と言ったり、強制!!といった強権を発動しても普及はしません。

そこで、現場のレベルに合わせて、まずは一部の機能だけで運用出来るように、クライアントアプリ@electronを作る事になりました。ウェブサービスの悪い点はフル機能をいきなり全面に全部出してしまう事ですね。あれなんとかならないのだろうか(天丼が食べたいのに、天ぷら懐石フルコースとか出されても困る)。

難易度:

今回使用するプロジェクトとモジュール

この他に、認証に必要なMicrosoft Azure-ADおよびMicrosoft Graph APIも使います。GASの時にも利用してるので合わせて参照してみてください。

事前準備

Azureでプロジェクト作成

ちょっと前までは、Application Registration Portalからアプリの登録ができたのですが、現在はMicrosoft Azureの一部になっています。Office365アカウントでなくとも、無料アカウントで始められるようになっているので、Microsoftアカウントが無い人はまずアカウントを作って、サインインしましょう。

さて、アプリの登録とそれに伴うクライアントIDなどの取得手順は以下の通り。

  1. アプリの登録にて登録を開始する
  2. アプリケーションの登録をクリックする
  3. 名前を入力、リダイレクトURIは「webを選択しhttp://localhost:3000/auth/callback」を入力(127.0.0.1はNG)
  4. 登録ボタンをクリックする
  5. 出てきた中で、「アプリケーション(クラと書かれているのがクライアントID」なので、このコードをメモしておく
  6. 左サイドバーより、「証明書とシークレット」をクリック
  7. 新しいクライアントシークレット」をクリックする
  8. 今回は特に有効期限を設けないで追加をクリック
  9. これで値に「クライアントシークレット」が生成されて手に入りました。このシークレットはこの時だけしか表示されないので、注意してください。
  10. つづけて、左サイドバーより「APIのアクセス許可」をクリックする
  11. Microsoft APIの中にある「Microsoft Graph」をクリックする。
  12. 委任されたアクセス許可」をクリックする
  13. デフォルトでUser.ReadがすでにONなので、offline_accessFiles.ReadWriteを検索してONにしましょう。
  14. アクセス許可の追加をクリックする
  15. 追加出来たら、xxxxxに管理者の同意を与えますをクリックします。すると、状態が緑色になります。
  16. 次に左サイドバーより「認証」をクリック
  17. 暗黙の付与にて、「アクセストークン」にチェックを入れる
  18. サポートされているアカウントの種類に於いては、「マルチテナント」にしておきました。
  19. 保存をクリック
  20. 概要のエンドポイントをクリックすると、いろいろなエンドポイントURLが出る。
  21. 概要のディレクトリ(テナントの数値はメモっておきます。あとでプログラム中で使用します。

※3.でWebを選ばないSPAを選んでしまうと、Proof Key for Code Exchange by OAuth Public Clientsといったエラーが出てしまい認証ができませんので注意。

※Teamsのメッセージ取得などの場合は、13.ではoffline_accessに加えて、Group.Read.All, Group.ReadWrite.Allを加えます。要求するscopeが異なるので作るアプリで何が必要なのか注意が必要です。Graph Explorerで調べて起きましょう。

図:アプリの登録から全ては始まります。

図:Graphを選択する

図:認証の設定変更に注意

electronプロジェクトの用意

Web APIを構築する時にも利用するexpressを使うのがポイントです。しかし、electronからexpressを扱う場合にはちょっと工夫が必要です。expressが立ち上げるWebサーバにelectronからアクセスする形を取る必要があるので、以下の手順で作業を行います。

まずは、express-generatorをグローバルインストールする

いつもならば、npm init -yでプロジェクトを作る所ですが、今回は以下のコマンドでexpress-generatorを使ってプロジェクトを作成します。今回はazureというディレクトリを作って作業をします。

azureというディレクトリが作られて、中にapp.js他たくさんの何かが生成されます。この段階で、以下のコマンドでテストをしてみます。

Windowsの場合、Firewallが作動して許可するかどうかを聞いてくるので、プライベートネットワークにチェックを入れてアクセスを許可するにチェックを入れる。そして、Chromeなどでhttp://localhost:3000/にアクセスした場合に、welcome to expressが表示されれば成功です。Ctrl+Cでnpm startしたサーバを停止できます。

※企業などでクライアントPCでこのアクセス許可が許されていない場合には、別途expressだけで認証用サーバを立てて、electronからそのサーバへアクセスする方式にしておけば、クリアできます。

図:expressによるWebサーバが立ち上がる際の画面

続けて、app.jsの入ってるフォルダに空のindex.jsを作成し、以下のコマンドで他のモジュールをインストールしておきます。

生成されているpackage.jsonを開いて、“main”: “index.js”,を追記して保存します。以下のような感じになるはずです。

index.jsにとりあえず以下のテスト用コードを追記してみる。npm startでexpressのサーバを起動した状態で、electron .で起動してみて、welcome to expressが表示されればテストはOK。

しかし、このままでは別途npm startでexpressを立ち上げて置いてから、electron .で起動する必要があるため、package.jsonscriptsのラインにnpm-run-allを使って複数のタスクを同時に起動するように細工をします。これで、テスト時は、electron .だけで全て起動します。

図:expressサーバをelectronから開けた

ログイン画面とトークンの取得

ここからが一番の峠道です。通常であればindex.jsに色々と記述する所ですが、今回の認証アプリの場合には、app.jsの方に記述する事になります。自動生成されたapp.jsにはすでに色々記述されているので、これを改造して使います。

今回は、こちらのソースコードを利用しています(少し改変を加えています)

ソースコード

app.js側コード

  • テナントのIDについてですが、commonにしてあると、認証ができません。
  • テナントのIDですが、冒頭で取得したディレクトリ(テナントの数値に置き換えてください。これがテナントIDになります。
  • サインイン時、コールバック時、サインアウト時の3つのアクションに対してそれぞれ処理を記述しています。
  • エラーハンドリングをコメントアウトしていますが、コメントアウト解除をするとデバッグがしにくくなりますので、リリース前に解除するようにしてください。
  • 認証が成功すると、user.txtという名前のファイルにAccess Tokenが書き出され、index.html側にそれらの情報が反映されます。
  • scopeはPortalで設定したものと同じものに加えて、profileは入れておいてください。認証結果が表示されなくなってしまうので。

図:テナントIDが重要です

index.html側コード

Githubにアップされているindex.htmlをそのまま利用させていただきました。ダウンロードしたindex.htmlは、viewsディレクトリに入れておけばオッケーです。

ejsを利用していて、express側からuserという配列を受け取ると、index.html内の所定の箇所にデータが展開される仕組みになっています。認証が完了し、Access Tokenなどを取得するとその情報が一目瞭然となります。個人的にはVue.js使ったほうがわかりやすい気がするけれど。

図:返ってきた値がindex.htmlへ反映される

実行結果と注意点

実行結果

electronを実行すると、signinsingoutの2つが出てきます。サインインをクリックするとelectron内でMicrosoftのログイン画面が出てきて、メールアドレスとパスワードを入力します。

サインイン時にScopeで設定したものについて承認を求められるので、「承諾」とする事で、認証が実行されて、Access Tokenなどが取得出来るようになります。

図:Microsoftのログイン画面が出てきた

図:承諾をする事でトークンが返却される

注意点

ログインクッキー

ログイン画面に於いて、パスワードを保存等すると、electronにcookieとして保存されます。よって、ここで保存されてしまうと次回以降ログイン時に利用されるので、ログイン画面が出てこなくなりますが、そのcookieは、expressが保存してるものではなく、electronが保持しています。

このcookieはキャッシュクリアではクリアされません。Windowsの場合保存されているパスは以下の場所で、CookiesというSQLiteファイルに格納されています。

アプリの名称は、package.jsonに記述されているname属性の名前が利用されています。このディレクトリにあるCookiesを削除すれば、再度ログインが出来るようになります。

アクセストークンについて

今回はuser.txtにAccess Tokenを書き出すようにしていますが、実際にアプリケーションとして利用する場合には、各OSの資格情報マネージャに格納すべきです。

今回はここでは紹介していませんが、以前紹介した記事において、node.jsから資格情報マネージャに情報を格納する「keytar」モジュールを使って、Access TokenやRefresh Tokenを格納しておくと良いでしょう。

また、アクセストークンは基本、1時間で失効します。そのままでは再度ログインして新しいAccess Tokenの取得が必要ですが、これでは不便です。Refresh Tokenを利用して新しいAccess Tokenを自動で取得する仕組みが別途必要になります。この辺りは次回の記事にて解説してみようと思います。

関連リンク

共有してみる: