Ajax에서 GAS와 통신 할 때 인증 오류가 발생하는 경우의 조치

개요



Ajax에서 GAS와 통신 할 때 스크립트 실행에 대한 권한을 부여하지 않으면 인증 오류가 발생합니다.
(스프레드 시트 작성 및 캘린더 취득 등)
대책으로 Ajax가 실패한 경우에만 GAS에서 렌더링 한 HTML을 표시하도록 결정했습니다.

※비동기 처리의 실장은 이쪽의 기사를 참고로 했습니다.
웹사이트의 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 appWho has access to the app: 全ユーザー

동작



실제 거동입니다. 종이 연극에서보십시오.

클라이언트 측 HTML 버튼을 누르면 confirmation이 표시됩니다.


GAS 측 HTML에 액세스할 때 평소 인증 대화 상자가 표시됩니다.
"허용"을 눌러 진행합니다.


GAS 측 HTML이 표시됩니다.


원래 페이지로 돌아가서 버튼을 다시 누르면 정상적으로 작동합니다.


비고



간단한 구현입니다만, 문제의 해결책으로서는 충분할까 생각합니다.
switch 문 안에서 다른 것과 다른 처리를 실행하고 있는 것이 기분 나쁘기 때문에 파라미터 자체를 따로 준비하는 것이 좋을지도 모릅니다.

좋은 웹페이지 즐겨찾기