Zarządzanie szczegółowymi uprawnieniami OAuth dla aplikacji Google Chat

Aplikacje do obsługi czatu, które korzystają z uwierzytelniania użytkowników, muszą obsługiwać szczegółowe uprawnienia OAuth, aby umożliwić użytkownikom przyznawanie podzbioru żądanych zakresów. Na przykład użytkownik może przyznać dostęp do swojego imienia, ale odmówić dostępu do kalendarza.

Obsługa szczegółowych uprawnień OAuth zależy od sposobu tworzenia aplikacji do obsługi czatu:

Google Apps Script

Jeśli tworzysz aplikację Google Chat za pomocą Apps Script, Apps Script automatycznie obsługuje szczegółowe uprawnienia OAuth. Upewnij się jednak, że kod obsługuje przypadki, w których użytkownik nie przyznaje wszystkich wymaganych zakresów. Postępuj zgodnie z instrukcjami podanymi w artykule Obsługa szczegółowych uprawnień OAuth w Google Apps Script.

Punkty końcowe HTTP

Jeśli tworzysz aplikację do Google Chat przy użyciu punktów końcowych HTTP, skonfiguruj kod tak, aby obsługiwał szczegółowe uprawnienia OAuth. Sprawdź, jakie zakresy autoryzacji przyznał użytkownik, i w razie potrzeby poproś o autoryzację brakujących lub wszystkich zakresów.

  1. W pliku manifestu aplikacji do obsługi czatu określ wymagane zakresy autoryzacji w polu oauthScopes. To pole jest częścią zasobu projects.deployments.

    Ten przykład wymaga zakresów autoryzacji chat.messages i 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. Aby sprawdzić, które zakresy użytkownik przyznał, zaznacz pole authorizationEventObject.authorizedScopes. Jeśli brakuje wymaganego zakresu, zwróć działanie requesting_google_scopes, aby poprosić użytkownika o udzielenie dostępu do brakujących zakresów.

    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']
            }
        })
    

    Java

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

    Aby poprosić o wszystkie zakresy powiązane z aplikacją Google Chat, ustaw dla parametru all_scopes wartość true:

    Node.js

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

    Python

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

    Java

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

Szczegółowe instrukcje znajdziesz w artykule Zarządzanie szczegółowymi uprawnieniami dodatków do Google Workspace HTTP.

Aplikacje Google Chat, które nie są dodatkami: zarządzanie szczegółowymi uprawnieniami OAuth dla aplikacji Google Chat

Jeśli utrzymujesz aplikację do obsługi czatu, która nie jest dodatkiem do Google Workspace, postępuj zgodnie z tymi instrukcjami, aby zarządzać szczegółowymi uprawnieniami OAuth.

Aplikacje do obsługi czatu w Google Chat w Apps Script, które nie są dodatkami

Jeśli aplikacja do Google Chat nie jest dodatkiem utworzonym za pomocą Apps Script, instrukcje w artykule Obsługa szczegółowych uprawnień OAuth w Apps Script działają z jednym zastrzeżeniem:

ScriptApp.requireScopes zatrzymuje wykonywanie skryptu, jeśli określone zakresy nie zostały przyznane, ale użytkownik widzi w Google Chat kartę konfiguracji zamiast ekranu zgody OAuth. Karta konfiguracji zawsze prosi użytkownika o przyznanie wszystkich żądanych zakresów, a nie tylko tych, które nie zostały jeszcze przyznane.

Aby przeprowadzać indywidualne kontrole autoryzacji na poziomie zakresu, użyj ScriptApp.getAuthorizationInfo, aby sprawdzić autoryzację i w razie potrzeby poprosić o nią za pomocą wiadomości prywatnej.

Poniższy przykład pokazuje, jak sprawdzić, czy użytkownik ma określone uprawnienia (np. dostęp do kalendarza), a jeśli ich nie ma, zwrócić wiadomość prywatną z wymaganym adresem URL autoryzacji.

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

Aplikacje w Google Chat HTTP, które nie są dodatkami

Jeśli aplikacja do obsługi czatu, która nie jest dodatkiem, jest usługą HTTP, samodzielnie zarządzasz przepływem OAuth 2.0.

Gdy pobierasz zapisany token lub wymieniasz kod autoryzacji, sprawdź, jakie zakresy zostały przyznane. Jeśli brakuje wymaganych zakresów, poproś użytkownika o ich autoryzację.

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'
)

Java

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