javascript - GAPI 的 OAuth - 首次登录 Javascript 后避免身份验证和授权

标签 javascript google-chrome-extension oauth google-api access-token

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

到目前为止我做了什么:

  • 我读到我需要一个刷新 token 来避免这种情况。但是,预计刷新 token 将在服务器端而不是客户端进行交换和存储(这是行不通的,因为后台脚本正在此处执行工作,即客户端)
  • 使用 gapi.auth.authorize 立即为真。这会导致有关外部可见性的错误。当我阅读其他内容时,他们建议在服务器内部使用它。我不确定如何在 chrome 扩展中做到这一点。
  • 在 getAuthToken 中将 interactive 设置为 false,这会在访问 token 过期后由于身份验证问题开始给出错误 401。

以下是我用于身份验证和授权的代码,在加载 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()
    })
};

list 是这样的:

{
  "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"]
    }
}

还有其他人遇到同样的问题吗?

最佳答案

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

这是来 self 的 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));
}

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

关于javascript - GAPI 的 OAuth - 首次登录 Javascript 后避免身份验证和授权,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52953850/

相关文章:

javascript - 暂停 JavaScript 执行以实现代码动画

javascript - 访问函数内的变量::TypeScript & Angular2

javascript - 如何确定您的扩展后台脚本在哪个浏览器中执行?

AngularJS + OAuth

javascript - OAuth 完整的 Javascript 访问权限,安全问题?

javascript - 检测任何对话框何时打开 jQuery

javascript 原型(prototype)对象 this 值

javascript - 如何在选项卡的主窗口对象上定义属性?

javascript - Chrome 扩展 - 将变量从 HTML 文件传递​​到 .js 文件

oauth - OAuth提供程序重定向后如何为用户提供JWT token ?