【问题标题】:Google hangout bot (Apps Script) using service account for authentication使用服务帐户进行身份验证的 Google 环聊机器人(Apps 脚本)
【发布时间】:2021-08-25 09:47:50
【问题描述】:

我正在通过 Apps Script 构建一个 google hangout bot 并对 google apis 进行了几次调用,我的问题是,当我认为我已正确设置它以调用 Google APIs 时,bot 当前请求 bot 用户的权限代表服务帐户而不是用户。

我在这里遵循了 google 提供的指导:https://developers.google.com/identity/protocols/oauth2/service-account

回复是:

{
   "azp": "XXXXXX", // Google service account id
   "aud": "XXXXXX", // Google service account id
   "scope": "https://www.googleapis.com/auth/calendar.readonly https://www.googleapis.com/auth/chat.bot https://www.googleapis.com/auth/script.external_request",
   "exp": "1629819391",
   "expires_in": "3569",
   "access_type": "online"
}

  • 然后我使用google访问令牌调用api

代码如下:

/*
 * 1. BUILD RS256 JWT: HEADER, CLAIM SET, SIGNATURE
 */
const createJwt = ({ privateKey, expiresInHours, input = {} }) => {      
  /*
  * The only signing algorithm supported by the Google OAuth 2.0 Authorization Server is RSA using SHA-256 hashing algorithm. 
  * This is expressed as RS256 in the alg field in the JWT header.
  */
  const header = { 
                    "alg":"RS256", 
                    "typ":"JWT", 
                    "kid": "XXXXXX", // service account private_key_id
                    "x5c": SERVICE_ACCOUNT_PUBLIC_KEY
                  };

  const now = Date.now();
  const expires = new Date(now);
  expires.setHours(expires.getHours() + expiresInHours);

  /*
  * iat: issued time 
  * exp: expiration time
  */
  const payload = {
    iat: Math.round(now / 1000),
    exp: Math.round(expires.getTime() / 1000)
  };

  /* add payload / claim set */
  Object.keys(input).forEach(function (key) {
    payload[key] = input[key];
  });

  const base64Encode = (text, json = true) => {
    const input = json ? JSON.stringify(text) : text;
    return Utilities.base64EncodeWebSafe(input).replace(/=+$/, '');
  };

  /* encode using the Base64url encoding */
  const toSign = `${base64Encode(header)}.${base64Encode(payload)}`;
  
  /*
  * Sign the UTF-8 representation of the input using SHA256withRSA (also known as RSASSA-PKCS1-V1_5-SIGN with the SHA-256 hash function) 
  * with the private key obtained from the Google API Console. 
  */
  const signatureBytes = Utilities.computeRsaSha256Signature(
    toSign,
    privateKey
  );
  
  /* The signature must then be Base64url encoded */
  const signature = base64Encode(signatureBytes, false);

  return `${toSign}.${signature}`;
};


/*
 * 2. SET JWT SCOPES & EXPIRY DATE
 * must be a short lived access token e.g. 1 hour, or else oauth2.googleapis.com/token throws an error
 */
const generateAccessToken = () => {
  const privateKey = SERVICE_ACCOUNT_PRIVATE_KEY;
  const scopes = ["https://www.googleapis.com/auth/script.external_request", "https://www.googleapis.com/auth/chat.bot", "https://www.googleapis.com/auth/calendar.readonly"];
  
  const accessToken = createJwt({
    privateKey,
    expiresInHours: 1,
    input: {
      iss: SERVICE_ACCOUNT_EMAIL,
      scope: scopes.join(" "),
      aud: "https://oauth2.googleapis.com/token",
    },
  });
  Logger.log(accessToken);
  return accessToken;
};


/*
 * 3. GENERATE JWT
 */
const jwt = generateAccessToken();

/*
 * 4. USE JWT TO GET GOOGLE ACCESS TOKEN FROM THE GOOGLE AUTHORIZATION SERVER
 */
const getGoogleAccessToken = () => UrlFetchApp.fetch("https://oauth2.googleapis.com/token", {
  method: "post",
  contentType: "application/x-www-form-urlencoded",
  payload: "grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=" + jwt
});

调用api示例

/**
 * Posts a message into the given space ID via the API,
 * using service account authentication.
 */
function postMessage(spaceId, message) {
  
 const CHAT_SPACE_URL = 'https://chat.googleapis.com/v1/spaces/' + spaceId + '/messages';
  
  Logger.log(JSON.parse(getGoogleAccessToken()));
  
 UrlFetchApp.fetch(CHAT_SPACE_URL, {
    method: 'post',
    headers: { 'Authorization': 'Bearer ' + JSON.parse(getGoogleAccessToken()).access_token },
    contentType: 'application/json',
    payload: JSON.stringify(message),
  });
  
  
}

非常感谢我出错的任何帮助:)

【问题讨论】:

  • 您是否删除了令牌文件并重新创建了它?
  • @RafaGuillermoI 我确实重命名了生成令牌的文件,在此过程中是否需要执行另一个步骤才能实施更新?

标签: google-apps-script google-api authorization service-accounts


【解决方案1】:

为了让您知道,我发现问题是我们公司内部的,我们无法通过 Google Workspace 域管理控制台添加 OAuth 范围。此代码将与实施的全域授权委托一起使用,因此我将把问题留在这里,以防它对其他人有所帮助。

【讨论】:

  • 请在您的回答中提供更多详细信息。正如目前所写的那样,很难理解您的解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-21
  • 2016-01-31
  • 2015-03-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多