LoginSignup
2
3

More than 3 years have passed since last update.

AjaxでGASと通信した時に認証エラーが出る場合の対策

Last updated at Posted at 2020-08-12

概要

AjaxでGASと通信した際にスクリプトの実行に対して権限を許可していないと認証エラーとなってしまいます。
(スプレッドシートの書き込みやカレンダーの取得等)
対策としてAjaxに失敗した場合に限り、GASでレンダリングしたHTMLを表示させることにしました。

※非同期処理の実装はこちらの記事を参考にさせていただきました。
WebサイトのJSからAjaxでGASの関数を最短で叩く

コード

まずはクライアント側です。ボタンを押したらメールアドレスやログインIDをアラート表示させる実装となっています。
また、ajaxの失敗時にも ?mode=authPage のパラメータ付きで別タブでWEBページを開くようにしています。
URLはajaxと同様にGASのエンドポイントを利用します。

クライアント側のサンプル.html
<!DOCTYPE html>
<html>
<head>
    <title>GASサンプル</title>
    <script src="https://code.jquery.com/jquery-3.3.1.js"></script>
</head>
<body>
    <button onclick="getMailAddress();">メールアドレスを取得</button>
    <button onclick="getUserName();">ユーザー名を取得</button>
    <script>
        function getMailAddress(){
            callAppsScript("mailAddress", function(data) {
                window.alert(data['rs']);
            });
        }
        function getUserName(){
            callAppsScript("userName", function(data) {
                window.alert(data['rs']);
            });
        }
        $(document).ready(function($) {
            // ajaxの処理
            window.callAppsScript = function(mode, callbackFunc) {
                const GAS_URL = "https://example.com/xxxxxxxxxxxxxxxxxxxxxx";
                let request = {'mode': mode};
                $.ajax({
                    type:"get",
                    url: GAS_URL,
                    data: request,
                    dataType: "jsonp",
                    success: function(data) {
                        callbackFunc(data);
                    }
                }).fail(function(jqXHR, textStatus, errorThrown ) {
                    console.log("XMLHttpRequest : " + jqXHR.status + "\n" + "textStatus : " + textStatus + "\n" + "errorThrown : " + errorThrown.message);
                    if(confirm('通信に失敗しました。認証ページを開きますか?')){
                        window.open(GAS_URL+'?mode=authPage', '_blank');
                    }
                });
            }
        });
    </script>
</body>
</html>

続いてGAS側です。パラメータに応じてメールアドレスやログインIDを返していますが、
mode=authPage の場合のみ index.html をレンダリングさせています。

main.js
function doGet(e) {
  let params = e.parameter;
  let res = {};
  switch(params.mode) {
    case 'mailAddress':
      res['rs'] = Session.getActiveUser().getEmail();
      break;
    case 'userName':
      res['rs'] = Session.getActiveUser().getUserLoginId();
      break;
    case 'authPage':
      let htmlOutput = HtmlService.createTemplateFromFile('index.html').evaluate();
      htmlOutput.setTitle('GAS認証ページ').addMetaTag('viewport','width=device-width, initial-scale=1')
      return htmlOutput;
    default:
      res['rs'] = 'パラメータが定義されていません。';
      break;
  }
  let callback = params.callback;
  let output = ContentService.createTextOutput();
  let responseText;
  if (callback) {
    responseText = callback + "(" + JSON.stringify(res) + ")";
    output.setMimeType(ContentService.MimeType.JAVASCRIPT);
  } else {
    responseText = JSON.stringify(res);
    output.setMimeType(ContentService.MimeType.JSON);
  }
  output.setContent(responseText);
  return output;
}

描画するのは簡易的なHTMLです。
GASのエディタページで ファイル->NEW->HTML と操作すると作成できます。

index.html
<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
  </head>
  <body>
    <span>認証が完了しました。このタブを閉じてアプリケーションに戻ってください。</span>
  </body>
</html>

ここまで出来たら 公開 -> WEBアプリケーションとして導入 から公開範囲を設定します。
例:
Execute the app as: User accessing the web app
Who has access to the app: 全ユーザー
gas.png

動作

実際の挙動です。紙芝居でご覧ください。

クライアント側HTMLのボタン押下でconfirmが表示されます。
confirm.png

GAS側のHTMLにアクセスする際にいつもの認証ダイアログが表示されます。
「許可」を押して進みます。
kengen.png

GAS側のHTMLが表示されます。
fin.png

元のページに戻って再度ボタンを押すと正常に機能します。
confirm - コピー.png

備考

簡単な実装ですが、問題の解決策としては十分かと思います。
switch文の中で他と違う処理を実行しているのが気持ち悪いのでパラメータ自体を別に用意した方がいいかもしれません。

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3