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

每個 Google 雲端硬碟檔案、資料夾和共用雲端硬碟都有相關聯的permissions資源。每個資源都會識別特定type (usergroupdomainanyone) 和role (ownerorganizerfileOrganizerwritercommenterreader) 的權限。舉例來說,某個檔案可能具有一項權限,可授予特定使用者 (type=user) 唯讀存取權 (role=reader),而另一項權限則可授予特定群組 (type=group) 的成員在檔案中新增註解的權限 (role=commenter)。

如需角色完整清單和各角色允許的作業,請參閱「角色和權限」。

權限的傳播方式

權限會從上層資料夾向下傳播至所有子項:

  • 預設為沿用:所有子檔案和子資料夾都會自動沿用上層資料夾的權限。
  • 無法減少子項目的權限:您無法移除或減少子項目的沿用權限。變更必須在上層資料夾進行,或是資料夾必須使用存取限制設定
  • 可擴展至子項:子項可授予較寬鬆的角色,例如在使用者擁有 role=reader 的資料夾中,授予檔案 role=writer
  • 移動時重新評估:將項目移至新的上層資料夾時,系統會重新評估並將新上層資料夾的權限套用至該項目及其子項。

檔案連結和存取控管

與特定使用者或群組共用檔案或資料夾時,存取項目的網址不會變更,系統也不會為每位使用者產生專屬連結。而是根據 fileId 產生單一固定連結。

Google 雲端硬碟會評估項目的 ACL,藉此控管存取權。使用者嘗試開啟連結時,雲端硬碟會根據存取控制清單 (ACL) 驗證已通過驗證的身分。如果權限遭到撤銷或到期,系統會將使用者從 ACL 中移除。如果使用者再次嘗試造訪連結,雲端硬碟會拒絕存取。

瞭解檔案功能

permissions 資源會定義「誰」有存取權 (存取控制清單),但不會直接指出目前使用者是否能在應用程式的 UI 中執行特定動作。

而是包含布林值 capabilities 欄位 (例如 canCommentcanSharecanDelete) 的集合,Google Drive API 會根據使用者的角色和項目設定動態計算這些欄位。files 資源

取得檔案功能

在算繪應用程式的 UI 時,請檢查 files.capabilities,而不是直接剖析權限:

  • 使用 fields=capabilities 呼叫 files.get 方法。詳情請參閱「傳回特定欄位」。
  • 使用傳回的布林值標記,在介面中啟用或停用對應的動作。舉例來說,如果 canCommentfalse,則停用留言功能。

共用雲端硬碟資源的適用情境

下表列出在不同位置和項目類型之間共用雲端硬碟資源時,所需的角色和條件:

位置 項目 必要的角色 主要限制
我的雲端硬碟 檔案或資料夾 ownerwriter ownerwritersCanShare=false
如要設定資料夾的限期存取,必須具備 reader 權限 (請參閱「設定到期日」一文)。
共用雲端硬碟 檔案 organizerfileOrganizerwriter writersCanShare 一律會視為 true
共用雲端硬碟 資料夾 organizer 如果 sharingFoldersRequiresOrganizerPermissionfalsefileOrganizer 也可以分享。
共用雲端硬碟 會員制 organizer 僅適用於 usergroup (不適用於網域)。

管理權限

下表列出 permissions 資源可用的方法:

方法 API 端點 重要參數 參考資料
建立 POST https://www.googleapis.com/drive/v3/files/{fileId}/permissions roletypeemailAddressdomain permissions.create
取得 GET https://www.googleapis.com/drive/v3/files/{fileId}/permissions/{permissionId} fields permissions.get
清單 GET https://www.googleapis.com/drive/v3/files/{fileId}/permissions pageSizesupportsAllDrivespageToken permissions.list
更新 PATCH https://www.googleapis.com/drive/v3/files/{fileId}/permissions/{permissionId} roleallowFileDiscovery permissions.update
刪除 DELETE https://www.googleapis.com/drive/v3/files/{fileId}/permissions/{permissionId} supportsAllDrives permissions.delete

建立權限

如要共用檔案、資料夾或共用雲端硬碟,請對 permissions 資源呼叫 create 方法,並使用 fileId。建立權限會在項目中新增 ACL 項目,並傳回指派的 permissionId

在要求主體中提供下列欄位:

  • role:要授予的存取層級 (例如 readercommenterwriter)。如需完整清單,請參閱「角色和權限」。
  • type:受讓人範圍 (usergroupdomainanyone)。
  • 受讓人 ID (視 type 而定):
    • emailAddresstypeusergroup 時為必要屬性。
    • domaintypedomain 時為必填。

以下程式碼範例說明如何建立權限。回應會傳回 permissions 資源的執行個體,包括指派的 permissionId

要求

POST https://www.googleapis.com/drive/v3/files/FILE_ID/permissions
{
  "role": "commenter",
  "type": "user",
  "emailAddress": "alex@altostrat.com"
}

回應

{
  "kind": "drive#permission",
  "id": "PERMISSION_ID",
  "type": "user",
  "role": "commenter"
}

與目標對象分享

目標對象是一種使用者群組 (例如部門或團隊),您可以建議使用者在共用項目時挑選這類群組。您可以鼓勵使用者與特定或部分目標對象 (而非整個機構) 共用項目。目標對象可協助您提升資料安全性和隱私,並讓使用者更輕鬆地適當共用資料。

如要與目標對象共用,請設定 type=domain 並將 domain 設為 <TARGET_AUDIENCE_ID>.audience.googledomains.com。如要瞭解如何在 Google 管理控制台中尋找或建立目標對象,請參閱「關於目標對象」。

如要瞭解使用者與目標對象的互動情形,請參閱連結分享的使用者體驗

取得權限

如要取得權限,請使用 fileIdpermissionId 路徑參數,呼叫 permissions 資源的 get 方法。如果您不知道權限 ID,請先列出所有權限

列出權限

如要列出檔案、資料夾或共用雲端硬碟的權限,請使用必要的 fileId 路徑參數,對 permissions 資源呼叫 list 方法。

您可以加入下列任一選用查詢參數,分頁或篩選回應:

  • pageSize (選用):每頁要傳回的權限數量上限。 如果未針對共用雲端硬碟中的檔案設定,最多會傳回 100 個結果。如果未針對不在共用雲端硬碟中的檔案設定,系統會傳回整個清單。

  • pageToken (選用):先前 list 呼叫傳來的頁面符記,用於擷取後續頁面。

  • supportsAllDrives (選用):要求存取權的應用程式是否同時支援「我的雲端硬碟」和共用雲端硬碟。

  • useDomainAdminAccess (選用):設為 true,以網域管理員身分發出要求。如果 fileId 參數參照共用雲端硬碟,且要求者是共用雲端硬碟所屬網域的管理員,系統就會授予要求者存取權。詳情請參閱「以網域管理員身分管理共用雲端硬碟」。

  • includePermissionsForView (選用):要在回覆中加入的其他檢視權限。僅支援 published

  • fields (選用):要在回應中傳回的特定欄位。根據預設,list 只會傳回 idtypekindrole。如要傳回其他欄位 (例如 permissionDetails),請使用這個參數指定。詳情請參閱「傳回特定欄位」。

判斷角色來源

如要變更檔案或資料夾的角色,您必須知道角色的來源。 如果是共用雲端硬碟,角色的來源可能是共用雲端硬碟的成員資格、資料夾的角色或檔案的角色。

如要判斷共用雲端硬碟或該硬碟中項目的角色來源,請使用 fileIdpermissionId 路徑參數,以及設為 permissionDetails 欄位的 fields 參數,對 permissions 資源呼叫 get 方法。

如要尋找 permissionId,請在 permissions 資源上使用 list 方法,並搭配 fileId 路徑參數。如要擷取 list 要求中的 permissionDetails 欄位,請將 fields 參數設為 permissions/permissionDetails

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

下列程式碼範例說明如何判斷角色來源。回應會傳回 permissions 資源的 permissionDetails。「inheritedFrom」欄位提供沿用權限的項目 ID。

要求

GET https://www.googleapis.com/drive/v3/files/FILE_ID/permissions/PERMISSION_ID?fields=permissionDetails&supportsAllDrives=true

回應

{
  "permissionDetails": [
    {
      "permissionType": "member",
      "role": "commenter",
      "inheritedFrom": "INHERITED_FROM_ID",
      "inherited": true
    },
    {
      "permissionType": "file",
      "role": "writer",
      "inherited": false
    }
  ]
}

更新權限

如要更新檔案或資料夾的權限,可以變更指派的角色。如要進一步瞭解如何找出角色來源,請參閱「判斷角色來源」。

  1. permissions 資源上呼叫 update 方法,並將 fileId 路徑參數設為相關聯的檔案、資料夾或共用雲端硬碟,以及將 permissionId 路徑參數設為要變更的權限。如要尋找 permissionId,請使用 permissions 資源的 list 方法和 fileId 路徑參數。

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

即使使用者或群組已是成員,您還是可以授予共用雲端硬碟中個別檔案或資料夾的權限。舉例來說,假設 Alex 是共用雲端硬碟的成員,role=commenter 不過,您的應用程式可以授予 Alex role=writer 共用雲端硬碟中檔案的存取權。在本例中,由於新角色比透過成員資格授予的角色權限更寬鬆,因此新權限會成為檔案或資料夾的有效角色

您可以透過修補程式語意套用更新,也就是對資源進行部分修改。您必須在要求中明確設定要修改的欄位。要求中未包含的欄位會保留現有值。詳情請參閱「處理部分資源」。

除了變更角色,當權限為 type 時,您也可以修改項目的可探索性。domainanyone如要讓共用檔案可供搜尋或不列出,請在修補程式要求中加入 allowFileDiscovery 布林值欄位。設為 true 後,即使指定目標對象未取得直接連結,項目仍會顯示在搜尋結果中。您不需要刪除並重新建立權限,即可變更這項設定。

下列程式碼範例說明如何將檔案或資料夾的權限從 commenter 變更為 writer。回應會傳回 permissions 資源的例項。

要求

PATCH https://www.googleapis.com/drive/v3/files/FILE_ID/permissions/PERMISSION_ID
{
  "role": "writer"
}

回應

{
  "kind": "drive#permission",
  "id": "PERMISSION_ID",
  "type": "user",
  "role": "writer"
}

使用批次要求更新多項權限

系統不支援對相同檔案、資料夾或共用雲端硬碟同時進行權限修改。無論您是修改同一位或不同收件者的權限,以及要求是來自單一應用程式或多位使用者,所有變更作業 (例如更新或刪除) 都會受到這項限制。

雲端硬碟會評估並更新項目的權限,做為單一 ACL。同時進行作業會導致競爭狀況,也就是「最後寫入者勝出」,這可能會無聲無息地覆寫權限變更,或觸發 sharingRateLimitExceeded 錯誤。

為避免衝突,請依序對同一項目執行權限變更,或使用批次要求,在單一要求中修改多項權限。

以下範例說明如何使用用戶端程式庫,以批次方式修改權限。

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
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
import {GoogleAuth} from 'google-auth-library';
import {google} from 'googleapis';

/**
 * Shares a file with a user and a domain.
 * @param {string} fileId The ID of the file to share.
 * @param {string} targetUserEmail The email address of the user to share with.
 * @param {string} targetDomainName The domain to share with.
 * @return {Promise<Array<string>>} A promise that resolves to an array of permission IDs.
 */
async function shareFile(fileId, targetUserEmail, targetDomainName) {
  // Authenticate with Google and get an authorized client.
  // TODO (developer): Use an appropriate auth mechanism for your app.
  const auth = new GoogleAuth({
    scopes: 'https://www.googleapis.com/auth/drive',
  });

  // Create a new Drive API client (v3).
  const service = google.drive({version: 'v3', auth});

  /** @type {Array<string>} */
  const permissionIds = [];

  // The permissions to create.
  const permissions = [
    {
      type: 'user',
      role: 'writer',
      emailAddress: targetUserEmail, // e.g., 'user@partner.com'
    },
    {
      type: 'domain',
      role: 'writer',
      domain: targetDomainName, // e.g., 'example.com'
    },
  ];

  // Iterate through the permissions and create them one by one.
  for (const permission of permissions) {
    const result = await service.permissions.create({
      requestBody: permission,
      fileId,
      fields: 'id',
    });

    if (result.data.id) {
      permissionIds.push(result.data.id);
      console.log(`Inserted permission id: ${result.data.id}`);
    } else {
      throw new Error('Failed to create permission');
    }
  }
  return permissionIds;
}

PHP

drive/snippets/drive_v3/src/DriveShareFile.php
<?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;
        }
    }
}

刪除權限

如要撤銷檔案或資料夾的存取權,請使用 fileIdpermissionId 路徑參數,呼叫 permissions 資源的 delete 方法。

您無法直接撤銷子項目的沿用權限,請改為更新或刪除上層資料夾的權限 (或使用存取限制設定)。

請注意,從上層項目移除使用者的存取權,只會撤銷從該上層項目繼承的權限。如果使用者也獲得子項目的直接權限,則該直接存取權會保留。如要確認權限已移除,請使用 fileId 呼叫 list

設定到期日

如要授予檔案或資料夾的臨時存取權,請在呼叫 createupdate 方法時,設定 expirationTime 欄位 (RFC 3339 日期時間)。

有效期限有下列限制:

  • 只能針對 usergroup 權限設定,不能針對 domainanyone 權限設定。
  • 時間必須設在未來,最長為一年。
  • 如果是資料夾,只有 reader 角色才能取得臨時存取權。