VBAでOAuth2.0認証 - 新方式を試してみた

2022年6月、IE11が終了するということで、以前にVBAにてOAuth2.0認証する手段として記事を投稿したことがあります。しかし、前回の記事では大きな課題を残したまま、実現は出来てるけれどそれまでの認証コードとは違い、別の手間が生じてしまっていてハードルが上がってしまいました。

しかしこの状況を打破するかもしれない、ChromeのDevToolsプロトコルを直接叩いてPuppeteerのように操縦出来、なおかつChromeのバージョンに合わせてWebDriverを更新する手間、当然自分のようにNode.js + PuppeteerをEXE化して間接的に動かすといったようなハードルもなく動かせるかも。ということで今回挑戦してみました。

※今回はGoogle APIのOAuth2.0認証を行うコードです。

今回利用するファイル等

今回のライブラリは、SeleniumVBAVBA-JSONWebDriverを必要とせず、単体でChromeのDevToolsを叩いて操縦する為、Puppeteerと同じ手法をVBAで実装したものになります。これにより、SeleniumやWebDriverを使わせないといったような職場でも利用することが出来るだけでなく、様々なハードルが下がり、尚且つWindows11以降でもVBAでChrome操縦をして自動化が可能になります。

また、ChromeだけじゃなくEdgeも操縦出来るように作られているということなので、Chromeの使用も許可しないような厳しい環境下でも利用が可能な素晴らしいライブラリになっています。ということで、今回はEdgeを使ってリクエストを送り全部標準の環境のみで完結することが出来ました。これで、OAuth2.0認証が使えるあらゆるREST APIを気兼ねなく叩くことが可能です。

VBAでOAuth2.0認証 - Windows11対応版

VBAからGoogle APIを叩いてみる – IE11廃止対応版

前回までの課題

課題のまとめ

Windows11の登場以降、VBAでREST APIを叩く事自体は出来ても、IE11が使えなくなった事でWebブラウザの操縦自動化やOAuth2.0の最初の認証の自動化は出来なくなってしまいました。そこで再登場したのがSelenium Basicなのですが色々と課題があり、また代替策として考えたNode.js + Puppeteerも決してハードルが低いというものではありませんでした。課題をまとめると

  • Seleniumの場合、Chromeのバージョンに合わせてWebDriverも随時更新をする必要性がある
  • WebDriverの自動更新用ライブラリも用意されていますが、そのための実装を加える必要性がある。
  • ただし、ChromeのバージョンアップとWebDriverのバージョンアップにはタイムラグがあるので、ケースによっては動かせない期間が生じる。
  • Selenium自体開発がすでに終了していて、インストール自体も管理者権限を通常要する(回避する策はあるけれど)
  • Node.js + Puppeteer + pkgライブラリを使って生成したEXEを叩く手法もあれど、ハードルが高い。都度変更したい場合、ビルドし直しが必要。
  • そもそも企業で使う場合、SeleniumもWebDriverもインストールを許可しないケースが多い

VBAのみで完結するライブラリが求められていましたが今回、ZeroInstall BrowserDriver for VBAの登場でそれが変わるかもというのが今回のテーマとなります。

仕組みはPuppeteerと同じChrome Devtools Protocol(CDP)を叩くというもので、これはChromeが持ってるローカルのポートをHTTPで叩いて操縦するものになりますが、とっても大変な作業です。これを手軽に実現出来るように実装した事で、前回までの課題をクリアする事ができました。

類似のクラスファイル

今回使用するライブラリの前に、CodeProjectにあるCDPを叩いて操作するライブラリを使った事がありますが、いくつか素直ではない部分がありました。今回利用するライブラリはその点非常に素直に綺麗にコードを書けるので、本ライブラリのほうがおススメ。

CodeProjectのライブラリは、現在のURLを取得するのにJSコードを発行したり、IE時代の書き方を踏襲してるがゆえにちょっと使いにくい。

事前準備

今回はGoogleのAPIを叩くためのOAuth2.0認証を実行し、Access Tokenを取得するまでを実装します。これによりVBAからGoogle Workspaceのアプリに対して命令を送れるようになり、可能性が一気に広がります。

注意点として、このライブラリは起動済みのChromeを捕獲して操縦することは出来ないので、常に新規にChromeを起動して操縦することになります。もし起動していたら一旦閉じてからコードは実行するようにしましょう。

注意点

今回のコードやサンプルについては、あくまで動かすということだけにフォーカスしてるサンプルです。よって、実務で利用する場合には、Client IDやClient Secretといったデータはコードの中には記述せずに安全な場所にファイルとして隔離し、できれば暗号化・複合化の手段を実装して漏洩しないようにアプリ側で実装が必要です。

また、おなじくAccess TokenやRefresh Tokenの値についても同様で、今回はiniファイルに書き出ししていますが、実際にはファイル化したものは暗号化・複合化する手段を実装して読み込み・書き込みをするべきです。

VBA側の準備

以下の手順で新規に用意しておいた拡張子がxlsmのExcelのブックに対して、ライブラリを全部インポートしておきます。

  1. こちらのページを開き、<>Codeをクリックして、Download ZIPをクリックする
  2. ZIPファイルを解凍すると、中にフォルダがありsrcを開くと複数のclsファイルが入っています。
  3. Excel VBAの編集画面を開く
  4. 2.のclsファイルをすべてインポートする(まとめて掴んで、VBA画面のプロジェクトペインにドラッグアンドドロップすると一気にインポートされます)

図:ライブラリはZIPで固められてる

図:無事に全部インポート出来ました。

Google側の準備

今回は、OAuth2.0認証を行うので、GCP側でClientIDやClient Secretなどを用意する必要があります。ここでは、クライアントIDとクライアントシークレットを取得します。以下の手順で取得しましょう。

  1. Google Cloud Consoleの認証情報作成を開く
  2. 認証情報を作成をクリックする
  3. OAuthクライアントIDを選択する
  4. クライアントIDの作成では、「ウェブアプリケーション」を選択する
  5. 承認済みのリダイレクト URIはVBA側と同じリダイレクトURLを指定します。
  6. 作成ボタンを押すと、クライアントIDクライアントシークレットが手に入るので控えておく。
  7. Cloud Consoleを閉じる

これで必要な情報の半分が手に入りました。この2つは大切なものなので、漏れたりしないように保存しておく必要があります。また、今回のケースは内部利用目的なので、OAuth同意画面に於いては、ユーザの種類は「内部」とし、スコープでは、VBA側で指定してるものを指定しています。

リダイレクトURLは自社のホームページなどのURLを指定します。すると認証後にそこにAuthenticated Codeが表示されるので、このコードを取得してさらにAccess Tokenを取得する仕組みです。適当なURLを指定すると、相手側のサーバでログが残り、そこにAuthenticated Codeが記載されてるのでセキュリティ的にはよろしくありません。今回はこのサイトのホームページを指定しています。

図:クライアントID、シークレット取得しておきましょう。

図:OAuth同意画面の設定

プロキシー設定を調べる

企業内で使う場合、ウェブアクセスにプロキシーを使ってる場合には、VBAからアクセスする場合もその設定を利用する必要性があります。プロキシーを経由しなければ外に出ることができないので、プログラムが動作しません。プロキシーの設定はいろいろなパターンがありますが、一般的な設定の調べ方は以下の通り。

サーバーのアドレスとポート番号について、http://を除外して、コロンでポート番号でつなげて利用します。(例:hiroproxy.net:8080)

  1. コントロールパネルより「インターネットオプション」を開く
  2. 「接続」タブを開き、「LANの設定」を開く
  3. この画面でプロキシーサーバの部分にアドレスとポート名が入ってるならばこれを控えておく。
  4. 場合によっては、詳細設定の中の「HTTP」で指定してるサーバーアドレスとポート番号を控えておく。
  5. 自動構成スクリプトを使ってる場合、そこに指定されてるアドレスのファイルの中に、様々なプロキシーアドレスが入っていますので、それを一旦ダウンロードして中身をテキストエディタで開いてみる(通常はpacというファイル)
  6. 5.のケースの場合、pacファイル内はIF文を使ってアクセスするサイト別にプロキシーが設定されてることが多いので、もっとも一般的なサイトアクセスもしくはGoogleについてだけ定義している場合には、そのサーバーアドレスとポート番号を控えておく。

図:プロキシー設定がない場合はこの作業は不要です。

ソースコード

認証コード

初回認証用のコード

以下は今回のライブラリを使ってのEdgeを使ったOAuth2.0認証のコードになります。クライアントIDやシークレット、リダイレクトURLを入力し、実行すると、認証用URLが開かれるのでログインする。許可を与えるとリダイレクト先に飛び自動的にブラウザは終了。

Authenticated Codeは引き続き、Access Tokenを取得するフローに送られてトークンと引き換えられます。認証が完了するまで無限ループで待機してる状態になります。また今回は特にAPIを叩くわけじゃないのですが、spreadsheetsを叩く想定でscopeに対象のスコープを入れてありますが、半角スペースで区切っていれる必要があります。

リファレンスには記述がなかったのですが、クラスファイル内に現在のURLを取得するメソッドが用意されていたので、driver.urlでURLを取得し、Parse関数(後述)にて、URLからAuthenticated Codeだけを抜き出します

Access Tokenを取得するコード

Authenticated Codeを元にアクセストークンほかを取得する為のコードです。初回のみRefresh Tokenを取得することが可能です。1時間でトークンは有効期限を迎えるのでexpireする時間などを含めて、iniファイルに書き出すようにしています。

トークン寿命が切れてるかチェック

API実行時にトークン寿命が切れているかどうかをチェックする関数です。以下の場合、残り50分を切っていたらフラグを1にして返すようにしていますので、お好みの時間をセットして自動リフレッシュにつなげることが可能です。

トークンをリフレッシュする

トークン寿命が切れていた場合に、リフレッシュトークンを使って新しいAccess Tokenを取得する為のコードです。新しく取得するデータにはリフレッシュトークンは含まれていないのでそのまま流用します。トークンとexpireする時間を再計算してiniファイルに書き出します。

URLからパラメータを取り出す関数

Access Tokenを取得する為のAuthenticated CodeはリダイレクトURLの中にcode=としてパラメータに含まれているため、これを取得する必要性があります。stackoverflowに便利な関数があった為、こちらを利用させていただきました。

以下の関数で、Parseに対して、「Parse(authcode, "code", vbString, "=", "&")」とするだけで、URLからcode=以下の文字列だけを抜き出すことが可能です。authcodeにはリダイレクト後のURLを格納します。

URLエンコードする関数

認証をするコードで利用してる、スコープをURLエンコードするための関数。64bitと32bitとではオフィスで利用できるコントロールが異なります。以下は64bit版オフィスでのURLエンコードを行う為の関数です。以下のコードはこちらのサイトから利用いたしました。

関連リンク

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)