概要
AjaxでGASと通信した際にスクリプトの実行に対して権限を許可していないと認証エラーとなってしまいます。
(スプレッドシートの書き込みやカレンダーの取得等)
対策としてAjaxに失敗した場合に限り、GASでレンダリングしたHTMLを表示させることにしました。
※非同期処理の実装はこちらの記事を参考にさせていただきました。
WebサイトのJSからAjaxでGASの関数を最短で叩く
コード
まずはクライアント側です。ボタンを押したらメールアドレスやログインIDをアラート表示させる実装となっています。
また、ajaxの失敗時にも ?mode=authPage
のパラメータ付きで別タブでWEBページを開くようにしています。
URLはajaxと同様にGASのエンドポイントを利用します。
<!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
をレンダリングさせています。
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
と操作すると作成できます。
<!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:
全ユーザー
##動作
実際の挙動です。紙芝居でご覧ください。
クライアント側HTMLのボタン押下でconfirmが表示されます。
GAS側のHTMLにアクセスする際にいつもの認証ダイアログが表示されます。
「許可」を押して進みます。
備考
簡単な実装ですが、問題の解決策としては十分かと思います。
switch文の中で他と違う処理を実行しているのが気持ち悪いのでパラメータ自体を別に用意した方がいいかもしれません。