首页 > 解决方案 > GAPI 的 OAuth - 初始登录 Javascript 后避免身份验证和授权

问题描述

我创建了一个 chrome 扩展程序,可以读取电子邮件、执行某些操作并使用 google 客户端 API for javascript 创建任务。我正在使用 chrome 身份进行身份验证和授权。扩展按预期工作。但是,它每隔一段时间就会要求签名。我想要的是在后台脚本中授权用户,这样他们就不需要在初始身份验证和授权之后一遍又一遍地执行此操作。

到目前为止我做了什么:

以下是我用于身份验证和授权的代码,在加载 google api 的客户端 js 文件后调用函数 onGoogleLibraryLoaded。

    var signin = function (callback) {
        chrome.identity.getAuthToken({interactive: true}, callback);
    };

    function onGoogleLibraryLoaded() {
        signin(authorizationCallback);
    }

    var authorizationCallback = function (data) {
        gapi.auth.setToken({access_token: data});
        gapi.client.load('tasks', 'v1')
        gapi.client.load('gmail', 'v1', function () {

            console.log("Doing my stuff after this ..")
        });
    };

更新:根据答案中的建议,我对代码进行了一些更改。但是,我仍然面临同样的问题。以下是更新的代码片段

jQuery.loadScript = function (url, callback) {
    jQuery.ajax({
        url: url,
        dataType: 'script',
        success: callback,
        async: false

   });
}
//This is the first thing that happens. i.e. loading the gapi client 
if (typeof someObject == 'undefined') $.loadScript('https://apis.google.com/js/client.js', 
    function(){
    console.log("gapi script loaded...")
});

//Every 20 seconds this function runs with internally loads the tasks and gmail 
// Once the gmail module is loaded it calls the function getLatestHistoryId()
setInterval(function() {
    gapi.client.load('tasks', 'v1')
    gapi.client.load('gmail', 'v1', function(){
        getLatestHistoryId()
    })
    // your code goes here...
}, 20 * 1000); // 60 * 1000 milsec

// This is the function that will get user's profile and when the response is received 
// it'll check for the error i.e. error 401 through method checkForError
function getLatestHistoryId(){
  prevEmailData = []

  var request = gapi.client.gmail.users.getProfile({
        'userId': 'me'
    });
    request.execute(function(response){
      console.log("User profile response...")
      console.log(response)
      if(checkForError(response)){
        return
      }
    })
}

// Now here I check for the 401 error. If there's a 401 error 
// It will call the signin method to get the token again. 
// Before calling signin it'll remove the saved token from cache through removeCachedAuthToken
// I have also tried doing it without the removeCachedAuthToken part. However the results were the same.  
// I have left console statements which are self-explanatory
function checkForError(response){
  if("code" in response && (response["code"] == 401)){
    console.log(" 401 found will do the authentication again ...")
    oooAccessToken = localStorage.getItem("oooAccessTokenTG")
    console.log("access token ...")
    console.log(oooAccessToken)
    alert("401 Found Going to sign in ...")

    if(oooAccessToken){
        chrome.identity.removeCachedAuthToken({token: oooAccessToken}, function(){
        console.log("Removed access token")
        signin()
      })  
    }
    else{
      console.log("No access token found to be remove ...")
      signin()
    }
    return true
  }
  else{
    console.log("Returning false from check error")
    return false
  }
}

// So finally when there is 401 it returns back here and calls 
// getAuthToken with interactive true 
// What happens here is that everytime this function is called 
// there is a signin popup i.e. the one that asks you to select the account and allow permissions
// That's what is bothering me. 
// I have also created a test chrome extension and uploaded it to chrome web store. 
// I'll share the link for it separately. 

var signin = function (callback) {
    console.log(" In sign in ...")
    chrome.identity.getAuthToken({interactive: true}, function(data){
        console.log("getting access token without interactive ...")
        console.log(data)

        gapi.auth.setToken({access_token: data});
        localStorage.setItem("oooAccessTokenTG", data)

        getLatestHistoryId()
    })
};

清单是这样的:

{
  "manifest_version": 2,

  "name": "Sign in Test Extension ",
  "description": "",
  "version": "0.0.0.8",
  "icons": {
      "16": "icon16.png", 
      "48": "icon48.png", 
      "128": "icon128.png" 
  },
  "content_security_policy": "script-src 'self' 'unsafe-eval' https://apis.google.com; object-src 'self'",
  "browser_action": {
   "default_icon": "icon.png",
   "default_popup": "popup.html"
  },
  "permissions": [   
    "identity",
    "storage"
   ],

  "oauth2": {
        "client_id": "1234.apps.googleusercontent.com",
        "scopes": [
            "https://www.googleapis.com/auth/gmail.readonly"
        ]
    },
    "background":{
      "scripts" : ["dependencies/jquery.min.js", "background.js"]
    }
}

还有其他人面临同样的问题吗?

标签: javascriptgoogle-chrome-extensionoauthgoogle-apiaccess-token

解决方案


我还在我的 chrome 扩展中使用身份 API 进行谷歌授权。当我的谷歌令牌过期时,我曾经获得 401 状态。所以我添加了一个检查,如果我收到我的请求的 401 状态响应,那么我将再次授权并获取令牌(它将在后台发生)并继续我的工作。

这是我的一个例子background.js

var authorizeWithGoogle = function() {
    return new Promise(function(resolve, reject) {
        chrome.identity.getAuthToken({ 'interactive': true }, function(result) {
            if (chrome.runtime.lastError) {
                alert(chrome.runtime.lastError.message);
                return;
            }
            if (result) {
                chrome.storage.local.set({'token': result}, function() {
                    resolve("success");
                });
            } else {
                reject("error");
            }
        });
    });
}

function getEmail(emailId) {
    if (chrome.runtime.lastError) {
        alert(chrome.runtime.lastError.message);
        return;
    }
    chrome.storage.local.get(["token"], function(data){
        var url = 'https://www.googleapis.com/gmail/v1/users/me/messages/id?alt=json&access_token=' + data.token;
        url = url.replace("id", emailId);
        doGoogleRequest('GET', url, true).then(result => {
            if (200 === result.status) {
                //Do whatever from the result
            } else if (401 === result.status) {
                /*If the status is 401, this means that request is unauthorized (token expired in this case). Therefore refresh the token and get the email*/
                refreshTokenAndGetEmail(emailId);
            }
        });
    });
}

function refreshTokenAndGetEmail(emailId) {
    authorizeWithGoogle().then(getEmail(emailId));
}

我不需要手动一次又一次地登录。谷歌令牌在后台自动刷新。


推荐阅读