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

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

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

Apps Script

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

نقطه‌های پایانی HTTP

اگر برنامه Chat خود را بااستفاده از نقطه‌های پایانی HTTP می‌سازید، کد خود را برای مدیریت اجازه‌های OAuth دقیق پیکربندی کنید. بررسی کنید کاربر کدام محدوده‌های مجوز را اعطا کرده است و درصورت لزوم، برای محدوده‌های ازدست‌رفته یا همه محدوده‌ها درخواست مجوز کنید.

  1. در فایل مانیفست برنامه Chat، محدوده‌های مجوز موردنیاز را در فیلد oauthScopes مشخص کنید. این فیلد بخشی از منبع projects.deployments است.

    مثال زیر به chat.messages و calendar.events محدوده‌های مجوز نیاز دارد:

    (قالب) JSON

    {
      "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": {},
        "calendar": {},
        "httpOptions": {}
      }
    }
    
  2. برای دیدن اینکه کاربر کدام محدوده‌ها را اعطا کرده است، فیلد authorizationEventObject.authorizedScopes را بررسی کنید. اگر یک محدوده موردنیاز وجود ندارد، requesting_google_scopes کنش را برگردانید تا کاربر برای محدوده‌های موردنیاز پیام‌واره دریافت کند.

    Node.js

    // 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;
    }
    

    Python

    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() != null
        ? event.getAuthorizationEventObject().getAuthorizedScopes()
        : null;
    if (authorizedScopes == null || !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();
    }
    

    برای درخواست همه محدوده‌های منسوب به برنامه Chat، all_scopes را روی true تنظیم کنید:

    Node.js

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

    Python

    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 مراجعه کنید.

برنامه‌های گپی که برافزا نیستند: مدیریت اجازه‌های OAuth دقیق برای برنامه‌های Google Chat

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

برنامه‌های Chat در Apps Script که برافزا نیستند

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

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

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

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

Apps Script

/**
* 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.
  // ...
}

برنامه‌های Chat پروتکل انتقال ابرمتن که برافزا نیستند

اگر برنامه Chat شما که برافزا نیست سرویس HTTP است، جریان OAuth 2.0 را خودتان مدیریت می‌کنید.

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

Node.js

// 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
});

Python

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();