مدیریت مجوزهای جزئی OAuth برای برنامه‌های Google Chat

برنامه‌های چت که از احراز هویت کاربر استفاده می‌کنند، باید از مجوزهای OAuth جزئی پشتیبانی کنند تا به کاربران اجازه دهند زیرمجموعه‌ای از حوزه‌های درخواستی را اعطا کنند. به عنوان مثال، یک کاربر ممکن است دسترسی به نام خود را اعطا کند اما دسترسی به تقویم خود را رد کند.

مدیریت مجوزهای جزئی OAuth بستگی به نحوه ساخت برنامه چت شما دارد:

اسکریپت برنامه‌ها

اگر برنامه چت خود را با استفاده از Apps Script می‌سازید، Apps Script مجوزهای OAuth جزئی را به طور خودکار مدیریت می‌کند. با این حال، مطمئن شوید که کد شما مواردی را که کاربر همه محدوده‌های درخواستی را اعطا نمی‌کند، مدیریت می‌کند. این روش بستگی به این دارد که آیا Apps Script شما یک افزونه Google Workspace است که Google Chat را با استفاده از Apps Script گسترش می‌دهد یا یک برنامه چت مستقل است که با Apps Script و رویدادهای تعاملی ساخته شده است.

افزونه‌های Google Workspace که Chat را گسترش می‌دهند

اگر برنامه چت خود را به عنوان یک افزونه Google Workspace می‌سازید که Google Chat را با استفاده از Apps Script گسترش می‌دهد ، دستورالعمل‌های موجود در بخش «مدیریت مجوزهای OAuth دانه‌ای در Apps Script» را دنبال کنید.

اسکریپت برنامه‌های مستقل، برنامه‌های چت

اگر برنامه چت خود را با استفاده از Apps Script و رویدادهای تعاملی می‌سازید، دستورالعمل‌های موجود در بخش «مدیریت مجوزهای OAuth دانه‌ای در Apps Script» با یک ملاحظه کار می‌کنند:

اگر محدوده‌های مشخص‌شده اعطا نشوند، اما کاربر به جای صفحه موافقت OAuth، یک کارت پیکربندی در چت ببیند، ScriptApp.requireScopes اجرای اسکریپت را متوقف می‌کند. کارت پیکربندی همیشه از کاربر می‌خواهد که به جای فقط محدوده‌های اعطانشده، تمام محدوده‌های درخواستی را اعطا کند.

برای ارائه بررسی‌های سطح دامنه مجوزدهی فردی، از ScriptApp.getAuthorizationInfo برای بررسی مجوز و در صورت لزوم درخواست مجوز با استفاده از یک پیام خصوصی استفاده کنید.

مثال زیر نحوه بررسی یک مجوز خاص (مانند دسترسی به تقویم) و در صورت عدم وجود، بازگرداندن یک پیام خصوصی با URL مجوز مورد نیاز را نشان می‌دهد.

اسکریپت برنامه‌ها

/**
* Responds to a MESSAGE event in Google Chat.
* Checks for required permissions and if missing asks for them.
*
* @param {Object} event the event object from Chat
* @return {Object} JSON response
*/
function onMessage(event) {
  // Check if the script has the necessary permissions.
  // In this example, the script checks for the "calendar.events" scope.
  var requiredScopes = ['https://www.googleapis.com/auth/calendar.events'];
  var authInfo = ScriptApp.getAuthorizationInfo(ScriptApp.AuthMode.FULL, requiredScopes);

  // If permissions are missing, return a message with the authorization URL.
  if (authInfo.getAuthorizationStatus() === ScriptApp.AuthorizationStatus.REQUIRED) {
    var authUrl = authInfo.getAuthorizationUrl();
    return {
      "text": "This action requires authorization. Please <" + authUrl + "|click here to authorize>.",
      "privateMessageViewer": {
        "name": event.user.name
      }
    };
  }

  // Permission granted; proceed with the application logic.
  // ...
}

نقاط پایانی HTTP

اگر برنامه چت خود را با استفاده از نقاط پایانی HTTP می‌سازید، برنامه چت شما باید از مجوزهای OAuth جزئی پشتیبانی کند.

افزونه‌های Google Workspace که Chat را گسترش می‌دهند

اگر برنامه چت خود را به عنوان یک افزونه Google Workspace می‌سازید (برای مثال، اگر برنامه‌های دیگر Google Workspace مانند Google Drive یا Gmail را گسترش می‌دهد)، فایل مانیفست و کد خود را طوری پیکربندی کنید که مجوزهای OAuth جزئی را مدیریت کند:

  1. در فایل مانیفست افزونه خود، فیلد granularOauthPermissionSupport را روی OPT_IN تنظیم کنید. برای کسب اطلاعات بیشتر در مورد فیلد granularOauthPermissionSupport ، به بخش مهاجرت به جریان مجوزهای granular OAuth مراجعه کنید.

    جی‌سون

    {
      "oauthScopes": [
        "https://www.googleapis.com/auth/chat.messages",
        "https://www.googleapis.com/auth/calendar.events"
      ],
      "addOns": {
        "common": {
          "name": "My Chat App",
          "logoUrl": "https://lh3.googleusercontent.com/..."
        },
        "chat": {},
        "httpOptions": {
          "granularOauthPermissionSupport": "OPT_IN"
        }
      }
    }
    
  2. برای مشاهده‌ی اینکه کاربر کدام حوزه‌ها را اعطا کرده است، در کد خود، فیلد authorizationEventObject.authorizedScopes را بررسی کنید. اگر حوزه‌ی مورد نیاز وجود ندارد، یک اکشن requesting_google_scopes را برگردانید تا کاربر حوزه‌های از دست رفته را درخواست کند.

    نود جی اس

    // Check for authorized scopes.
    const authorizedScopes = req.body.authorizationEventObject.authorizedScopes || [];
    if (!authorizedScopes.includes('https://www.googleapis.com/auth/chat.messages')) {
      // Respond with a request for the missing scope.
      res.send({
        'requesting_google_scopes': {
          'scopes': ['https://www.googleapis.com/auth/chat.messages']
        }
      });
      return;
    }
    

    پایتون

    from flask import jsonify, request
    
    # Check for authorized scopes.
    event_data = request.get_json()
    authorized_scopes = event_data.get('authorizationEventObject', {}).get('authorizedScopes', [])
    if 'https://www.googleapis.com/auth/chat.messages' not in authorized_scopes:
        # Respond with a request for the missing scope.
        return jsonify({
            'requesting_google_scopes': {
                'scopes': ['https://www.googleapis.com/auth/chat.messages']
            }
        })
    

    جاوا

    import com.google.gson.JsonArray;
    import com.google.gson.JsonObject;
    import java.util.List;
    
    // Check for authorized scopes.
    List<String> authorizedScopes = event.getAuthorizationEventObject().getAuthorizedScopes();
    if (!authorizedScopes.contains("https://www.googleapis.com/auth/chat.messages")) {
      // Respond with a request for the missing scope.
      JsonObject requestingGoogleScopes = new JsonObject();
      JsonArray scopes = new JsonArray();
      scopes.add("https://www.googleapis.com/auth/chat.messages");
      requestingGoogleScopes.add("scopes", scopes);
    
      JsonObject response = new JsonObject();
      response.add("requesting_google_scopes", requestingGoogleScopes);
      return response.toString();
    }
    

    برای درخواست تمام scope های مرتبط با افزونه، all_scopes را روی true تنظیم کنید:

    نود جی اس

    res.send({
      'requesting_google_scopes': { 'all_scopes': true }
    });
    

    پایتون

    from flask import jsonify
    
    return jsonify({
        'requesting_google_scopes': { 'all_scopes': True }
    })
    

    جاوا

    import com.google.gson.JsonObject;
    
    JsonObject requestingGoogleScopes = new JsonObject();
    requestingGoogleScopes.addProperty("all_scopes", true);
    
    JsonObject response = new JsonObject();
    response.add("requesting_google_scopes", requestingGoogleScopes);
    return response.toString();
    

برای دستورالعمل‌های دقیق، به مدیریت مجوزهای جزئی برای افزونه‌های HTTP Google Workspace مراجعه کنید.

برنامه‌های چت HTTP مستقل

اگر برنامه چت شما یک سرویس HTTP مستقل است (نه یک افزونه Google Workspace)، جریان OAuth 2.0 را خودتان مدیریت می‌کنید.

وقتی یک توکن ذخیره شده را بازیابی می‌کنید یا کد مجوز را مبادله می‌کنید، بررسی کنید که کدام حوزه‌ها اعطا شده‌اند. اگر حوزه‌های مورد نیاز وجود ندارند، از کاربر بخواهید که آنها را مجاز کند.

نود جی اس

// 1. List authorized scopes.
const fs = require('fs');
const tokens = JSON.parse(fs.readFileSync('token.json'));
const grantedScopes = tokens.scope.split(' ');

// 2. Detect missing scopes.
const requiredScopes = ['https://www.googleapis.com/auth/chat.messages'];
const missingScopes = requiredScopes.filter(scope => !grantedScopes.includes(scope));

if (missingScopes.length > 0) {
  // 3. Request missing scopes.
  const authUrl = oauth2Client.generateAuthUrl({
    access_type: 'offline',
    scope: missingScopes,
    include_granted_scopes: true
  });
  res.redirect(authUrl);
}

// To request all scopes instead of just the missing ones:
const allScopesAuthUrl = oauth2Client.generateAuthUrl({
  access_type: 'offline',
  scope: requiredScopes,
  include_granted_scopes: true
});

پایتون

from flask import redirect
from google.oauth2.credentials import Credentials

# 1. List authorized scopes.
credentials = Credentials.from_authorized_user_file('token.json')
granted_scopes = set(credentials.scopes)

# 2. Detect missing scopes.
required_scopes = {'https://www.googleapis.com/auth/chat.messages'}
missing_scopes = required_scopes - granted_scopes

if missing_scopes:
    # 3. Request missing scopes.
    flow.scope = list(missing_scopes)
    auth_url, _ = flow.authorization_url(
        access_type='offline',
        include_granted_scopes=True
    )
    return redirect(auth_url)

# To request all scopes instead of just the missing ones:
flow.scope = list(required_scopes)
all_scopes_auth_url, _ = flow.authorization_url(
    access_type='offline',
    include_granted_scopes='true'
)

جاوا

import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeRequestUrl;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

// 1. List authorized scopes.
// The "user" string is the user ID for which to load credentials.
Credential credential = flow.loadCredential("user");
Collection<String> grantedScopes = credential.getScopes();

// 2. Detect missing scopes.
// The `requiredScopes` variable contains a list of the OAuth scopes
// that your app requires to function. Define this variable with the
// scopes needed by your application.
List<String> requiredScopes = Arrays.asList("https://www.googleapis.com/auth/chat.messages");
List<String> missingScopes = new ArrayList<>();
for (String scope : requiredScopes) {
  if (!grantedScopes.contains(scope)) {
    missingScopes.add(scope);
  }
}

if (!missingScopes.isEmpty()) {
  // 3. Request missing scopes.
  GoogleAuthorizationCodeRequestUrl urlBuilder = new GoogleAuthorizationCodeRequestUrl(
      clientId, redirectUri, missingScopes)
      .setAccessType("offline")
      .set("include_granted_scopes", "true");
  String authUrl = urlBuilder.build();
  response.sendRedirect(authUrl);
}

// To request all scopes instead of just the missing ones:
GoogleAuthorizationCodeRequestUrl allScopesUrlBuilder = new GoogleAuthorizationCodeRequestUrl(
    clientId, redirectUri, requiredScopes)
    .setAccessType("offline")
    .set("include_granted_scopes", "true");
String allScopesAuthUrl = allScopesUrlBuilder.build();

برای اطلاعات بیشتر، به مجوزهای Granular OAuth مراجعه کنید.