为什么使用“immediate:false”的gapi.auth.authorize不会关闭弹出窗口并触发回调?

时间:2014-10-21 08:03:13

标签: javascript authentication google-chrome-extension google-oauth

我正在开展一些Chrome扩展程序。谷歌开发者控制台已经配置好并且最终使用了gapi,但是我已经遇到了问题,比如用户体验。

所以这是我尝试实现的情景:

  1. 尝试使用Google Chrome登录用户进行身份验证。
  2. 如果失败,请尝试使用immediate:true。
  3. 通过gapi.auth.authorize进行身份验证
  4. 如果失败,请尝试使用immediate:false。
  5. 通过gapi.auth.authorize进行身份验证

    这种作品。我得到了要求许可的弹出窗口,我单击“接受”,然后popus变为空白,标题设置为"正在连接..." (不会关闭)并且永远不会触发回调函数。

    我知道访问被授予,因为当我单击“接受并重新加载”页面时,它可以使用immediate:true进行授权,并且我的扩展程序可以正常工作。

    我检查了几个问题,主题和问题,在Google搜索答案时询问了不同的查询,我找到了这个解决方案:

    1. setTimeout(checkAuth,1) - 尝试过,没有成功。
    2. 我推断出立即:在立即后不能立即调用false:true,所以我试一试并尝试使用immediate进行身份验证:false为first。相同的结果。
    3. 我尝试在其回调中添加gapi.auth.init和checkingAuth(也使用setTimeout)。
    4. 所以这里有一些代码(background.js)。对不起它看起来像意大利面条,我是JS的初学者。

      function respond(interactive, sendResponse) {
          xhrWithAuth('GET',
              'https://www.googleapis.com/gmail/v1/users/me/profile',
              interactive, // false
              onUserMailFetched, sendResponse);
      
          function xhrWithAuth(method, url, interactive, callback, sendResponse) {
              var access_token;
              var retry = true;
      
              getToken();
              // 1. trying to use Chrome user
              function getToken() {
                  chrome.identity.getAuthToken({
                      interactive: interactive
                  }, function (token) {
                      if (chrome.runtime.lastError) {
                      // 2. here lastError is User is not signed in. Calling onUserMailFetched
                          callback(chrome.runtime.lastError, null, null, sendResponse);
                      }
                      access_token = token;
                      requestStart();
                  });
              }
              // I guess not important in topic
              function requestStart() {
                  var xhr = new XMLHttpRequest();
                  xhr.open(method, url);
                  xhr.setRequestHeader('Authorization', 'Bearer ' + access_token);
                  xhr.onload = requestComplete;
                  xhr.send();
              }
              // I guess not important in topic
              function requestComplete() {
                  if (this.status == 401 && retry) {
                      retry = false;
                      chrome.identity.removeCachedAuthToken({
                              token: access_token
                          },
                          checkAuth_neverCalled);
                  } else {
                      callback(null, this.status, this.response, sendResponse);
                  }
              }
              // I guess not important in topic
              function checkAuth_neverCalled() {
                  console.log("checking auth when getAuthToken fails");
                  gapi.auth.authorize({
                      client_id: OAUTH2_CLIENT_ID,
                      scope: OAUTH2_SCOPES,
                      immediate: false
                  }, handleAuthResult);
      
                  // Handle the result of a gapi.auth.authorize() call.
                  function handleAuthResult(authResult) {
                      console.log("authenticated: ", authResult);
                      if (authResult) {
                          // do something with data
                      } else {
                          consoel.log("failed");
                      }
                  }
              }
          }
      
          // This is important part.
          function onUserMailFetched(error, status, response, sendResponse) {
              if (!error && status == 200) {
                  // do something with data
              } else {
               // 3. as we have error at first call, we checkAuth with immediate = true
                  setTimeout(function () {
                      checkAuthWhenNotLogged(sendResponse, true);
                  }, 10);
              }
          }
          // This is important part.
          function checkAuthWhenNotLogged(sendResponse, immediateVal) {
              gapi.auth.authorize({
                  client_id: OAUTH2_CLIENT_ID,
                  scope: OAUTH2_SCOPES,
                  immediate: immediateVal
              }, handleAuthResult);
      
              // Handle the result of a gapi.auth.authorize() call.
              // 5. But this function is never called again (when called with false).
              function handleAuthResult(authResult) {
                  if (authResult) {
                  // 4. and this is called when checkAuth with true fail. We call checkAuth (itself) with false.
                      if (authResult.error == "immediate_failed") {
                          gapi.auth.init(function () {
                              setTimeout(function () {
                                  checkAuthWhenNotLogged(sendResponse, false);
                              }, 10);
                          });
                      } else {
                      // yay, we are authneticated and can call gmail service
                          gapi.client.load('gmail', 'v1', function () {
                              var request = gapi.client.gmail.users.getProfile({
                                  'userId': 'me'
                              });
                              request.execute(function (profile) {
                                  // do something with data
                              });
                          });
                      }
                  } else {
                      console.log("failed");
                  }
              }
          }
      }
      

      任何提示,链接或解决方案都会被贬低。

1 个答案:

答案 0 :(得分:2)

好的,这就是我为OAuth2所做的工作。

场景如下:

  1. 尝试使用Google Chrome登录用户进行身份验证。
  2. 如果失败,请尝试使用immediate:true。
  3. 通过gapi.auth.authorize进行身份验证
  4. 如果失败,请尝试使用chrome.identity.launchWebAuthFlow
  5. 首先,我需要解释为什么launchWebAuthFlow没有提前工作。正如我所提到的,我配置了Google Developers Console,并为Chrome应用创建了密钥和客户端ID。这对launchWebAuthFlow来说是错误的。它应该是带有配置重定向URL的Web应用程序。

    在Chrome扩展程序中,您可以通过以下方式获取重定向网址:     var redirectURL = chrome.identity.getRedirectURL(" suffix"); 它会创建这样的东西:     HTTPS:// {APPID} .chromiumapp.org /

    您需要在客户端ID配置中将其设置为重定向链接。在我的情况下,我不得不在js代码中更改使用过的客户端ID。

    以下是适用于我的代码:

    (...)
    var redirectURL = chrome.identity.getRedirectURL();
    var options = {
        'interactive': true,
        url: 'https://accounts.google.com/o/oauth2/auth?' +
            'scope=profile email' +
            '&response_type=token' +
            '&client_id=' + OAUTH2_CLIENT_ID_WEB +
            '&redirect_uri=' + redirectURL
    }
    chrome.identity.launchWebAuthFlow(options, function (redirectUri1) {
        if (chrome.runtime.lastError) {
            console.log(chrome.runtime.lastError);
        } else {
            // redirectUri is a link with access_token param inside, we need to extract it
            var paramName = "access_token"
            var results = new RegExp(paramName + '=([^&#]*)').exec(redirectUri1);
            if (results == null) {
                console.log("not found");
            } else {
                console.log(results[1] || 0);
                access_token = results[1]; // here we set the token
                requestStart(); // here I launch google api request
            }
        };
    });
    (...)
    function requestStart() {
            // url = 'https://www.googleapis.com/plus/v1/people/me'
            // method = 'GET'
            var xhr = new XMLHttpRequest();
            xhr.open(method, url);
            xhr.setRequestHeader('Authorization', 'Bearer ' + access_token);
            xhr.onload = requestComplete;
            xhr.send();
        }
    
    function requestComplete() {
        if (this.status == 401 && retry) {
            retry = false;
            chrome.identity.removeCachedAuthToken({
                    token: access_token
                },
                checkAuth);
        } else {
            callback(this.status, this.response);
        }
    }
    

    希望有人能利用这一点。我知道我花了太多时间在这上面。