【GAS】GASで作成したWebサイトでBasic認証(もどき)を実装する
GASで作成したWebサイトはデフォルトで「自分のみ」「Googleアカウントを持つ全員」「全員」という公開範囲を設定可能です。さらにアクセスしているユーザの情報を取得することで細かなアクセス制御も可能ですが、Googleアカウントの情報を取得するため厳密に制限ができる反面、事前にアクセスを許可するメールアドレスをリストに追加し、閲覧ユーザにユーザ情報の取得を許可してもらう必要があります。今回紹介する方法では事前のメールアドレス把握やユーザ情報の取得は不要です。ただし通常のbasic認証同様、IDとPWがわかればアクセスできてしまう点にはご注意ください。
この記事では以下のステップでコードを解説しています。
非表示目次を読み込み中…1. 仕組み
ID/PWの認証にはGASのProperties Serviceクラスの「スクリプトプロパティ」と「ユーザプロパティ」を使用します。スクリプトプロパティは全てのユーザがアクセスできるプロパティ、ユーザプロパティはスクリプトを動かすユーザのみがアクセスできるプロパティです。スクリプトプロパティへ事前にID/PWを設定しておき、ユーザプロパティへユーザが入力したID/PWを保存をします。
GET時にID/PWの認証を行い、結果に応じて認証画面と認証後の画面を出し分けます。認証が成功した場合にユーザプロパティにID/PWを保存して、次回以降はGET時に保存した認証データを参照します。
2. コード一覧
「ファイルを追加」から以下のファイルを作成し、各々コードを書き換えてください。※ ID/PWをコードに直接記述すると、ライブラリとして公開されるURLを利用した際に外部のユーザが取得できてしまうため、{ID} {PW}から変更しないでください
- gas.gs
- auth.html
- index.html
サーバー側の処理部分になります
gasfunction setup() { PropertiesService.getScriptProperties().setProperty('auth', JSON.stringify({id:"{ID}", pw:"{PW}"})); } function doGet() { const authOwn = JSON.parse(PropertiesService.getUserProperties().getProperty('auth_users')); if (tryAuth(authOwn) == "success"){ var htmlOutput = HtmlService.createTemplateFromFile("index").evaluate(); } else { var htmlOutput = HtmlService.createTemplateFromFile("auth").evaluate(); } return htmlOutput; } function tryAuth(authOwn) { if (authOwn != null){ const auth = JSON.parse(PropertiesService.getScriptProperties().getProperty('auth')); if (auth.id == authOwn.id && auth.pw == authOwn.pw) { PropertiesService.getUserProperties().setProperty('auth_users', JSON.stringify(authOwn)); return "success"; } } return "fail"; } function deleteAuth(){ PropertiesService.getUserProperties().deleteAllProperties(); }auth.html認証画面としてフロントに表示するものです
html<!DOCTYPE html> <html> <head> <base target="_top"> </head> <body> <form> <input name="id" type="text" placeholder="ID" required="required" autocomplete="off"> <input name="pw" type="password" placeholder="PW" required="required" autocomplete="off"> <input type="submit" value="認証"> </form> <script> window.addEventListener("load", function(){ document.querySelector("form").addEventListener("submit", function (event) { event.preventDefault(); }); }); function handleSubmit() { document.querySelector("input[type=submit]").disabled = true; const authOwn = document.querySelector("form"); google.script.run .withFailureHandler(onFailure) .withSuccessHandler(onSuccess) .tryAuth(authOwn); } function onSuccess(rslt){ if (rslt == "success"){ window.open("<?= ScriptApp.getService().getUrl() ?>", "_top"); } else { alert("認証情報が一致しません"); document.querySelector("input[type=submit]").disabled = false; } } function onFailure(){ alert("正常に完了しませんでした"); document.querySelector("input[type=submit]").disabled = false; } </script> </body> </html>index.html認証済の場合にフロントで表示するものです
html<!DOCTYPE html> <html> <head> <base target="_top"> </head> <body> 認証成功 <button type="button">認証情報削除</button> <script> function reset(){ google.script.run .withFailureHandler(reload) .withSuccessHandler(reload) .deleteAuth(); } function reload(){ window.open("<?= ScriptApp.getService().getUrl() ?>", "_top"); } </script> </body> </html>3. セットアップ方法
初回起動を行うGASの編集画面からsetup()を実行開いたGoogleアカウントの権限確認画面で許可を選択
設定画面を開く左側のタブからプロジェクトの設定を選択
IDとPWを入力画面最下部までスクロールし、「スクリプトプロパティを編集」を押下し、{ID}と{PW}の部分を変更
IDとPWを保存変更後に「スクリプトプロパティを保存」を押下し、変更した内容を保存する
デプロイを作成「デプロイ」から以下の通り設定した新しいデプロイを作成する
必ず「ウェブアプリケーションにアクセスしているユーザー」で実行するように設定してください
動作確認生成されたウェブアプリURLにアクセスする
4. コード解説
※ JavaScriptの挙動については詳細は割愛しています
gas.gsgas.gsに記述するコードについて解説します。
setup():スクリプトプロパティのデフォルト値を設定PropertiesServiceクラスのgetScriptProperties()メソッドでスクリプトプロパティを取得取得したプロパティに対してPropertiesクラスのsetProperty(key, value)メソッドでキーauthに対してidとpwを保存このとき、Object型ではプロパティの値として扱えないため、JSON形式に変換を行う
gasPropertiesService.getScriptProperties().setProperty('auth', JSON.stringify({id:"{ID}", pw:"{PW}"}));doGet():認証結果別にフロントへ返すHTMLファイルを定義webサイト読み込み時(GET時)に動作
PropertiesServiceクラスのgetUserProperties()メソッドでユーザプロパティを取得取得したプロパティに対してPropertiesクラスのgetProperty(key)メソッドでキーauth_usersに紐づく値を取得JSON形式で保存されているため、Object型に戻して変数authOwnへ格納
gasconst authOwn = JSON.parse(PropertiesService.getUserProperties().getProperty('auth_users'));関数tryAuthへ変数authOwnで認証をリクエスト戻り値に応じたhtmlファイルを変数htmlOutputにHtmlOutputオブジェクトとして格納HtmlOutputオブジェクトはHtmlServiceクラスのcreateTemplateFromFile(filename)メソッドでhtmlファイルをHtmlTemplateオブジェクトに変換し、HtmlTemplateクラスのevaluate()メソッドで変換して生成
今回はhtml内にGASコードが含まれるためcreateTemplateFromFile(filename)を使用
gasif (tryAuth(authOwn) == "success"){ var htmlOutput = HtmlService.createTemplateFromFile("index").evaluate(); } else { var htmlOutput = HtmlService.createTemplateFromFile("auth").evaluate(); }フロントで出力する内容として変数htmlOutputを返す
gasreturn htmlOutput;tryAuth(authOwn) :認証を実行変数authOwnが空でない場合、PropertiesServiceクラスのgetScriptProperties()メソッドでスクリプトプロパティを取得取得したプロパティに対してPropertiesクラスのgetProperty(key)メソッドでキーauthに紐づく値を取得JSON形式で保存されているため、Object型に戻して変数authへ格納
さらに変数authOwnと変数authのid/pwがどちらも一致した場合、PropertiesServiceクラスのgetUserProperties()メソッドでユーザープロパティを取得取得したプロパティに対してPropertiesクラスのsetProperty(key, value)メソッドでキーauth_usersに対してidとpwを保存このとき、Object型ではプロパティの値として扱えないため、JSON形式に変換を行う
認証結果としてsuccessを返す
gasif (authOwn != null){ const auth = JSON.parse(PropertiesService.getScriptProperties().getProperty('auth')); if (auth.id == authOwn.id && auth.pw == authOwn.pw) { PropertiesService.getUserProperties().setProperty('auth_users', JSON.stringify(authOwn)); return "success"; } }変数authOwnが空の場合もしくは変数authOwnと変数authのidとpwが一致しなかった場合、認証結果としてfailを返す
gasreturn "fail";deleteAuth():ユーザプロパティをクリアPropertiesServiceクラスのgetUserProperties()メソッドでユーザープロパティを取得取得したプロパティに対してPropertiesクラスのdeleteAllProperties()メソッドで全てのキーとそれに紐づく値を削除
gasPropertiesService.getUserProperties().deleteAllProperties();auth.htmlauth.htmlに記述するJavascriptについて解説します。
window.addEventListener(“load”, function):イベントを追加画面読み込み完了後に自動実行
form要素のsubmit時にsubmitのデフォルトイベントをキャンセルするイベントを追加
jsdocument.querySelector("form").addEventListener("submit", function (event) { event.preventDefault(); });handleSubmit():GAS側へ認証をリクエスト重複送信防止の為、submitボタンを非活性化
jsdocument.querySelector("input[type=submit]").disabled = true;変数authOwnにform要素を格納
jsconst authOwn = document.querySelector("form");GAS側の関数tryAuthへ変数authOwnで認証をリクエスト認証結果を問わず関数実行が失敗した場合、関数onFailureを動作させる認証結果を問わず関数実行が成功した場合、関数onSuccessを動作させる
jsgoogle.script.run .withFailureHandler(onFailure) .withSuccessHandler(onSuccess) .tryAuth(authOwn);onSuccess(rslt):フロントへ返すHTMLファイルを変更するためリロード認証が成功した場合、現在のURLに再アクセスを行いGAS側の関数doGetを動作させる現在のURLはGASのScriptAppクラスのgetService()メソッドでウェブアプリのServiceオブジェクトを取得し、getUrl()メソッドで取得
GASのwebサイトはiframe構造のためJSのlocation.hrefでは取得できません
失敗した場合、認証が失敗した旨をアラートで通知し、submitボタンを活性化
jsif (rslt == "success"){ window.open("<?= ScriptApp.getService().getUrl() ?>", "_top"); } else { alert("認証情報が一致しません"); document.querySelector("input[type=submit]").disabled = false; } onFailure():関数実行失敗を通知関数実行が失敗した旨をアラートで通知
jsalert("正常に完了しませんでした");submitボタンを活性化
jsdocument.querySelector("input[type=submit]").disabled = false;index.htmlindex.htmlに記述するJavascriptについて解説します。
reset():GAS側へ認証情報削除をリクエストGAS側の関数deleteAuthへ認証情報削除をリクエスト関数実行結果を問わず、関数reloadを動作させる
jsgoogle.script.run .withFailureHandler(reload) .withSuccessHandler(reload) .deleteAuth();reload():フロントへ返すHTMLファイルを変更するためリロード現在のURLに再アクセスを行いGAS側の関数doGetを動作させる現在のURLはGASのScriptAppクラスのgetService()メソッドでウェブアプリのServiceオブジェクトを取得し、getUrl()メソッドで取得※ GASのwebサイトはiframe構造のためJSのlocation.hrefでは取得できません
jswindow.open("<?= ScriptApp.getService().getUrl() ?>", "_top");まとめ
GASでBasic認証もどきを実装する方法を解説しました。コピペだけで実装できますので、社内や仲間内での共有などにぜひ活用してみてください。
参考Class HtmlService | Apps Script | Google for DevelopersGoogle for Developers参考Class PropertiesService | Apps Script | Google for DevelopersGoogle for Developersこの記事は役に立ちましたか?
もし参考になりましたら、下記のボタンで教えてください。
0 【ステップ2】Go言語の開発環境のセットアップ 前の記事 【ステップ3】"Hello, World!"、最初のGoプログラム 次の記事関連記事
【GAS】GASでPOSTをリクエストしてGASで処理するGoogleWorkspace内にGoogleフォームを設置し、ファイルのアップロードをさせたかったのですが、共有フォルダに格納した時点で画像のアップロード機能が使用できなくなりました。それならばGASでフォームを自作しようと思ったのですが、アクセスユーザの取得にはアクセスユーザでWebサイトを動
【GAS】GASでGET/POSTの受取データを処理するベストプラクティスこの記事をまとめたときにGASのPOST受け取り仕様が複雑だと感じたものの、解説されているサイトが少なかったため、GETと併せてPOSTされたデータを受け取る方法をまとめました。この記事では以下のステップでコードを解説しています。非表示目次を読み込み中...GETを受け取る
Googleドライブのフォルダを一括コピー!GASで実現する自動化手順GoogleDrive内のフォルダはドラッグ・アンド・ドロップや切り取り+貼り付けで簡単に移動できますが、コピーは制限がかかっているため、まとめて複製を行うことができません。今回はGASを使って指定フォルダ以下の全階層をまるっとコピーするコードをご紹介します。この記事では以下のステップでコ
【GAS】スプレッドシートからセルの値を取得・追加するベストプラクティスGASでスプレッドシートを操作する場合の基本となるセルの値の取得・追加の方法を解説します。この記事では以下のステップでコードを解説しています。非表示目次を読み込み中...1. スプレッドシートを取得するGASでスプレッドシートの操作を行うにはSpreadsheetA