共用檔案、資料夾和雲端硬碟

每個 Google 雲端硬碟檔案、資料夾和共用雲端硬碟都有相關的權限資源。每項資源都會識別特定 type (使用者、群組、網域、任何人) 和 role 的權限,例如「加註者」或「讀取者」。舉例來說,某檔案可能包含授予特定使用者 (type=user) 唯讀存取權 (role=reader) 的權限,而其他權限則允許特定群組 (type=group) 的成員在檔案 (role=commenter) 中新增註解。

如需完整的角色清單及每個角色所允許的作業,請參閱角色

共用雲端硬碟資源的情境

共用情境有 5 種:

  1. 如要在「我的雲端硬碟」中共用檔案,使用者必須具備 role=writer 以上的版本。

    • 如果檔案的 writersCanShare 布林值設為 False,使用者就必須使用 role=owner

    • 如果具有 role=writer 的使用者俱有存取權到期日的暫時存取權,就無法共用檔案。

    詳情請參閱「新增到期日」。

  2. 如要在「我的雲端硬碟」中共用資料夾,使用者必須具備 role=writer 或更高的版本。

    • 如果檔案的 writersCanShare 布林值設為 False,使用者必須具備較寬鬆的 role=owner

    • 具有「role=writer」的「我的雲端硬碟」資料夾不允許暫時存取權 (設有到期日和時間)。

  3. 如要在共用雲端硬碟中共用檔案,使用者必須具備 role=writer 以上的版本。

    • writersCanShare 設定不適用於共用雲端硬碟中的項目。 系統會將其視為一律設為 True
  4. 使用者必須擁有 role=organizer,才能在共用雲端硬碟中共用資料夾。

    • 如果共用雲端硬碟的 sharingFoldersRequiresOrganizerPermission 限制設為 False,則擁有 role=fileOrganizer 的使用者就可以共用該共用雲端硬碟中的資料夾。
  5. 使用者必須擁有 role=organizer,才能管理共用雲端硬碟成員資格。只有使用者和群組是共用雲端硬碟的成員。

權限傳播

資料夾的權限清單會向下傳播,而所有子項檔案和資料夾都會沿用父項的權限。每當權限或階層有所改變時,系統都會透過所有巢狀資料夾重複執行傳播。例如,如果檔案存在於資料夾中,而該資料夾在另一個資料夾中移動,則新資料夾的權限會傳播至檔案。如果新資料夾授予使用者新的角色,例如「寫入者」,則會覆寫其原本的角色。

反之,如果檔案沿用資料夾的 role=writer,並移至其他提供「讀取者」角色的資料夾,則檔案現在會沿用 role=reader

您無法從共用雲端硬碟的檔案或資料夾中移除沿用的權限。您必須針對這些繼承的直接或間接父項來調整這些權限。您可以從「我的雲端硬碟」或「與我共用」下方的項目移除沿用的權限。

相反地,您可以覆寫「我的雲端硬碟」中檔案或資料夾的權限。因此,如果檔案沿用「我的雲端硬碟」資料夾中的 role=writer,則可在檔案上設定 role=reader,以降低其權限等級。

功能

權限資源最終無法判斷目前的使用者對檔案或資料夾執行的動作。相反地,Files 資源包含一系列布林值的 capabilities 欄位,用於指出某個動作能否在檔案或資料夾上執行。Google Drive API 會根據與檔案或資料夾相關聯的目前使用者權限資源設定這些欄位。

舉例來說,當 Alex 登入應用程式並嘗試共用檔案時,Alex 的角色會與檔案的權限相關檢查。如果角色允許共用檔案,則與檔案相關的 capabilities (例如 canShare) 會根據角色相對地填入內容。如果小亞想要共用檔案,您的應用程式會檢查 capabilities,確保 canShare 已設為 true

建立權限

建立權限時,請務必填寫下列 2 個欄位:

  • typetype 可識別權限範圍 (usergroupdomainanyone)。type=user 權限適用於特定使用者,type=domain 權限則適用於特定網域中的所有人。

  • rolerole 欄位會識別 type 可執行的作業。例如,具備 type=userrole=reader 的權限會授予特定使用者對檔案或資料夾的唯讀存取權。或者,擁有 type=domainrole=commenter 的權限可讓網域中的所有人新增檔案註解。如需完整的角色清單及每個角色所允許的作業,請參閱角色

當您建立 type=usertype=group 的權限時,還必須提供 emailAddress,將特定使用者或群組連結至權限。

建立 type=domain 的權限時,您也必須提供 domain,以便將特定網域連結至權限。

建立權限的步驟如下:

  1. permissions.create 方法與相關檔案或資料夾使用 fileId
  2. 在要求主體中,識別 typerole
  3. 如果 type=usertype=group,請提供 emailAddress。如果為 type=domain,請提供 domain

使用目標對象

目標對像是一種使用者群組 (例如部門或團隊),您可以將這類群組當做使用者的建議共用對象。您可以鼓勵使用者與更明確或受限的目標對象共用項目,不要與整個機構共用。目標對象可協助您改善資料的安全性和隱私性,並讓使用者更輕鬆地共用資料。詳情請參閱「關於目標對象」一文。

如何使用目標對象:

  1. 登入 Google 管理控制台。

    您必須使用具備超級管理員權限的帳戶登入。

  2. 依序前往「選單」 >「目錄」 >「目標對象」

  3. 在「目標對象清單」中,按一下目標對象的名稱。如要建立目標對象,請參閱建立目標對象

  4. 複製目標對象網址的專屬 ID:https://admin.google.com/ac/targetaudiences/ID

  5. 使用 type=domain 建立權限,並將 domain 欄位設為 ID.audience.googledomains.com

如要查看使用者與目標對象的互動,請參閱連結共用設定的使用者體驗

擷取檔案、資料夾或共用雲端硬碟的所有權限

使用 permissions.list 方法擷取檔案、資料夾或共用雲端硬碟的所有權限。

驗證使用者權限

開啟檔案時,系統會檢查檔案功能,並轉譯 UI 以反映目前使用者的權限。舉例來說,如果使用者沒有 canComment 的功能,您應在使用者介面中停用留言功能。

如要檢查功能,請使用設為 capabilities 欄位的 fileIdfields 參數呼叫 files.get

如要進一步瞭解如何使用 fields 參數傳回欄位,請參閱「傳回檔案的特定欄位」一文。

判斷共用雲端硬碟檔案和資料夾的角色

如要變更檔案或資料夾的角色,你必須知道角色的來源。 如為共用雲端硬碟,角色的角色取決於共用雲端硬碟的成員資格、資料夾的角色或檔案的角色。

如要判斷共用雲端硬碟的角色或該雲端硬碟中的項目,請呼叫 permissions.get,並將 fileIdpermissionIdfields 參數設為 permissionDetails 欄位。如要尋找 permissionId,請搭配 fileId 使用 permissions.list

這個欄位會列出使用者、群組或網域的所有沿用和直接檔案權限。

變更權限

如要變更檔案或資料夾的權限,您可以變更已指派的角色:

  1. 呼叫 permissions.update,並提供變更權限的 permissionId,以及相關聯檔案、資料夾或共用雲端硬碟的 fileId。如要尋找 permissionId,請搭配 fileId 使用 permissions.list

  2. 在要求中,找出新的 role

您可以授予共用雲端硬碟中個別檔案或資料夾的權限,即使使用者或群組已經是成員也一樣。舉例來說,小亞擁有 role=commenter 做為共用雲端硬碟的成員的一部分。不過,應用程式可以針對共用雲端硬碟中的檔案授予小莉 role=writer。在這種情況下,由於新角色的權限比透過其授予的角色所授予的權限較高,因此新權限會成為檔案或資料夾的有效角色

撤銷檔案或資料夾的存取權

如要撤銷檔案或資料夾的存取權,請使用 fileIdpermissionId 呼叫 delete 來刪除權限。

您可以刪除「我的雲端硬碟」中的項目,藉此刪除沿用的權限。 刪除沿用的權限會撤銷項目和子項目 (如果有的話) 的存取權。

共用雲端硬碟中的項目無法撤銷沿用的權限。請改為更新或撤銷上層檔案或資料夾的權限。

delete 作業也可用於刪除直接套用至共用雲端硬碟檔案或資料夾的權限。

將檔案擁有權轉移給同一機構中的其他 Google Workspace 帳戶

「我的雲端硬碟」中現有的檔案擁有權可以從某個 Google Workspace 帳戶轉移至同一個機構中的其他帳戶。擁有共用雲端硬碟的機構會擁有該雲端硬碟中的檔案。因此,系統不支援擁有權在共用雲端硬碟中的檔案和資料夾。共用雲端硬碟的發起人可以將共用雲端硬碟中的項目移至自己的「我的雲端硬碟」,也可以將擁有權轉移給他們。

如要轉移「我的雲端硬碟」中的檔案擁有權,請執行下列任一操作:

  • 建立檔案權限,授予特定使用者 (type=user) 擁有者存取權 (role=owner)。

  • 使用 role=owner 更新現有檔案的權限,並將擁有權轉移給指定使用者 (transferOwnership=true)。

將檔案擁有權從一個個人帳戶轉移到另一個個人帳戶

檔案擁有權可以在一個個人帳戶之間轉移。不過,除非潛在新的擁有者明確同意轉移,否則雲端硬碟不會在 2 個使用者帳戶之間轉移檔案擁有權。將檔案擁有權從某個個人帳戶轉移至另一個:

  1. 目前的擁有者會透過建立或更新潛在新擁有者的檔案權限,啟動擁有權轉移。權限必須包含以下設定:role=writertype=userpendingOwner=true。如果新擁有者為潛在擁有者建立權限,系統會傳送電子郵件給電子郵件通知,說明他們被要求取得檔案擁有權。

  2. 新擁有者要建立或更新檔案權限,藉此接受擁有權轉移要求。權限必須包含以下設定:role=ownertransferOwnership=true。如果新擁有者正在建立新的權限,系統會發送電子郵件通知給前擁有者,指出擁有權已轉移。

檔案轉移後,原先擁有者的角色會降級為 writer

透過批次要求變更多項權限

強烈建議您使用批次要求來修改多個權限。

以下範例為透過用戶端程式庫執行批次權限修改作業。

Java

drive/snippets/drive_v3/src/main/java/ShareFile.java
import com.google.api.client.googleapis.batch.BatchRequest;
import com.google.api.client.googleapis.batch.json.JsonBatchCallback;
import com.google.api.client.googleapis.json.GoogleJsonError;
import com.google.api.client.googleapis.json.GoogleJsonResponseException;
import com.google.api.client.http.HttpHeaders;
import com.google.api.client.http.HttpRequestInitializer;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.services.drive.Drive;
import com.google.api.services.drive.DriveScopes;
import com.google.api.services.drive.model.Permission;
import com.google.auth.http.HttpCredentialsAdapter;
import com.google.auth.oauth2.GoogleCredentials;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/* Class to demonstrate use-case of modify permissions. */
public class ShareFile {

  /**
   * Batch permission modification.
   * realFileId file Id.
   * realUser User Id.
   * realDomain Domain of the user ID.
   *
   * @return list of modified permissions if successful, {@code null} otherwise.
   * @throws IOException if service account credentials file not found.
   */
  public static List<String> shareFile(String realFileId, String realUser, String realDomain)
      throws IOException {
        /* Load pre-authorized user credentials from the environment.
         TODO(developer) - See https://developers.google.com/identity for
         guides on implementing OAuth2 for your application.application*/
    GoogleCredentials credentials = GoogleCredentials.getApplicationDefault()
        .createScoped(Arrays.asList(DriveScopes.DRIVE_FILE));
    HttpRequestInitializer requestInitializer = new HttpCredentialsAdapter(
        credentials);

    // Build a new authorized API client service.
    Drive service = new Drive.Builder(new NetHttpTransport(),
        GsonFactory.getDefaultInstance(),
        requestInitializer)
        .setApplicationName("Drive samples")
        .build();

    final List<String> ids = new ArrayList<String>();


    JsonBatchCallback<Permission> callback = new JsonBatchCallback<Permission>() {
      @Override
      public void onFailure(GoogleJsonError e,
                            HttpHeaders responseHeaders)
          throws IOException {
        // Handle error
        System.err.println(e.getMessage());
      }

      @Override
      public void onSuccess(Permission permission,
                            HttpHeaders responseHeaders)
          throws IOException {
        System.out.println("Permission ID: " + permission.getId());

        ids.add(permission.getId());

      }
    };
    BatchRequest batch = service.batch();
    Permission userPermission = new Permission()
        .setType("user")
        .setRole("writer");

    userPermission.setEmailAddress(realUser);
    try {
      service.permissions().create(realFileId, userPermission)
          .setFields("id")
          .queue(batch, callback);

      Permission domainPermission = new Permission()
          .setType("domain")
          .setRole("reader");

      domainPermission.setDomain(realDomain);

      service.permissions().create(realFileId, domainPermission)
          .setFields("id")
          .queue(batch, callback);

      batch.execute();

      return ids;
    } catch (GoogleJsonResponseException e) {
      // TODO(developer) - handle error appropriately
      System.err.println("Unable to modify permission: " + e.getDetails());
      throw e;
    }
  }
}

Python

drive/snippets/drive-v3/file_snippet/share_file.py
from __future__ import print_function

import google.auth
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError


def share_file(real_file_id, real_user, real_domain):
    """Batch permission modification.
    Args:
        real_file_id: file Id
        real_user: User ID
        real_domain: Domain of the user ID
    Prints modified permissions

    Load pre-authorized user credentials from the environment.
    TODO(developer) - See https://developers.google.com/identity
    for guides on implementing OAuth2 for the application.
    """
    creds, _ = google.auth.default()

    try:
        # create drive api client
        service = build('drive', 'v3', credentials=creds)
        ids = []
        file_id = real_file_id

        def callback(request_id, response, exception):
            if exception:
                # Handle error
                print(exception)
            else:
                print(f'Request_Id: {request_id}')
                print(F'Permission Id: {response.get("id")}')
                ids.append(response.get('id'))

        # pylint: disable=maybe-no-member
        batch = service.new_batch_http_request(callback=callback)
        user_permission = {
            'type': 'user',
            'role': 'writer',
            'emailAddress': 'user@example.com'
        }
        batch.add(service.permissions().create(fileId=file_id,
                                               body=user_permission,
                                               fields='id',))
        domain_permission = {
            'type': 'domain',
            'role': 'reader',
            'domain': 'example.com'
        }
        domain_permission['domain'] = real_domain
        batch.add(service.permissions().create(fileId=file_id,
                                               body=domain_permission,
                                               fields='id',))
        batch.execute()

    except HttpError as error:
        print(F'An error occurred: {error}')
        ids = None

    return ids


if __name__ == '__main__':
    share_file(real_file_id='1dUiRSoAQKkM3a4nTPeNQWgiuau1KdQ_l',
               real_user='gduser1@workspacesamples.dev',
               real_domain='workspacesamples.dev')

Node.js

drive/snippets/drive_v3/file_snippets/share_file.js
/**
 * Batch permission modification
 * @param{string} fileId file ID
 * @param{string} targetUserEmail username
 * @param{string} targetDomainName domain
 * @return{list} permission id
 * */
async function shareFile(fileId, targetUserEmail, targetDomainName) {
  const {GoogleAuth} = require('google-auth-library');
  const {google} = require('googleapis');

  // Get credentials and build service
  // TODO (developer) - Use appropriate auth mechanism for your app
  const auth = new GoogleAuth({
    scopes: 'https://www.googleapis.com/auth/drive',
  });
  const service = google.drive({version: 'v3', auth});
  const permissionIds = [];

  const permissions = [
    {
      type: 'user',
      role: 'writer',
      emailAddress: targetUserEmail, // 'user@partner.com',
    },
    {
      type: 'domain',
      role: 'writer',
      domain: targetDomainName, // 'example.com',
    },
  ];
  // Note: Client library does not currently support HTTP batch
  // requests. When possible, use batched requests when inserting
  // multiple permissions on the same item. For this sample,
  // permissions are inserted serially.
  for (const permission of permissions) {
    try {
      const result = await service.permissions.create({
        resource: permission,
        fileId: fileId,
        fields: 'id',
      });
      permissionIds.push(result.data.id);
      console.log(`Inserted permission id: ${result.data.id}`);
    } catch (err) {
      // TODO(developer): Handle failed permissions
      console.error(err);
    }
  }
  return permissionIds;
}

PHP

drive/snippets/drive_v3/src/DriveShareFile.php
use Google\Client;
use Google\Service\Drive;
function shareFile()
{
    try {
        $client = new Client();
        $client->useApplicationDefaultCredentials();
        $client->addScope(Drive::DRIVE);
        $driveService = new Drive($client);
        $realFileId = readline("Enter File Id: ");
        $realUser = readline("Enter user email address: ");
        $realDomain = readline("Enter domain name: ");
        $ids = array();
            $fileId = '1sTWaJ_j7PkjzaBWtNc3IzovK5hQf21FbOw9yLeeLPNQ';
            $fileId = $realFileId;
            $driveService->getClient()->setUseBatch(true);
            try {
                $batch = $driveService->createBatch();

                $userPermission = new Drive\Permission(array(
                    'type' => 'user',
                    'role' => 'writer',
                    'emailAddress' => 'user@example.com'
                ));
                $userPermission['emailAddress'] = $realUser;
                $request = $driveService->permissions->create(
                    $fileId, $userPermission, array('fields' => 'id'));
                $batch->add($request, 'user');
                $domainPermission = new Drive\Permission(array(
                    'type' => 'domain',
                    'role' => 'reader',
                    'domain' => 'example.com'
                ));
                $userPermission['domain'] = $realDomain;
                $request = $driveService->permissions->create(
                    $fileId, $domainPermission, array('fields' => 'id'));
                $batch->add($request, 'domain');
                $results = $batch->execute();

                foreach ($results as $result) {
                    if ($result instanceof Google_Service_Exception) {
                        // Handle error
                        printf($result);
                    } else {
                        printf("Permission ID: %s\n", $result->id);
                        array_push($ids, $result->id);
                    }
                }
            } finally {
                $driveService->getClient()->setUseBatch(false);
            }
            return $ids;
    } catch(Exception $e) {
        echo "Error Message: ".$e;
    }

}

.NET

drive/snippets/drive_v3/DriveV3Snippets/ShareFile.cs
using Google.Apis.Auth.OAuth2;
using Google.Apis.Drive.v3;
using Google.Apis.Drive.v3.Data;
using Google.Apis.Requests;
using Google.Apis.Services;

namespace DriveV3Snippets
{
    // Class to demonstrate use-case of Drive modify permissions.
    public class ShareFile
    {
        /// <summary>
        /// Batch permission modification.
        /// </summary>
        /// <param name="realFileId">File id.</param>
        /// <param name="realUser">User id.</param>
        /// <param name="realDomain">Domain id.</param>
        /// <returns>list of modified permissions, null otherwise.</returns>
        public static IList<String> DriveShareFile(string realFileId, string realUser, string realDomain)
        {
            try
            {
                /* Load pre-authorized user credentials from the environment.
                 TODO(developer) - See https://developers.google.com/identity for
                 guides on implementing OAuth2 for your application. */
                GoogleCredential credential = GoogleCredential.GetApplicationDefault()
                    .CreateScoped(DriveService.Scope.Drive);

                // Create Drive API service.
                var service = new DriveService(new BaseClientService.Initializer
                {
                    HttpClientInitializer = credential,
                    ApplicationName = "Drive API Snippets"
                });

                var ids = new List<String>();
                var batch = new BatchRequest(service);
                BatchRequest.OnResponse<Permission> callback = delegate(
                    Permission permission,
                    RequestError error,
                    int index,
                    HttpResponseMessage message)
                {
                    if (error != null)
                    {
                        // Handle error
                        Console.WriteLine(error.Message);
                    }
                    else
                    {
                        Console.WriteLine("Permission ID: " + permission.Id);
                    }
                };
                Permission userPermission = new Permission()
                {
                    Type = "user",
                    Role = "writer",
                    EmailAddress = realUser
                };

                var request = service.Permissions.Create(userPermission, realFileId);
                request.Fields = "id";
                batch.Queue(request, callback);

                Permission domainPermission = new Permission()
                {
                    Type = "domain",
                    Role = "reader",
                    Domain = realDomain
                };
                request = service.Permissions.Create(domainPermission, realFileId);
                request.Fields = "id";
                batch.Queue(request, callback);
                var task = batch.ExecuteAsync();
                task.Wait();
                return ids;
            }
            catch (Exception e)
            {
                // TODO(developer) - handle error appropriately
                if (e is AggregateException)
                {
                    Console.WriteLine("Credential Not found");
                }
                else
                {
                    throw;
                }
            }
            return null;
        }
    }
}