共享文件、文件夹和云端硬盘

每个 Google 云端硬盘文件、文件夹和共享云端硬盘都具有关联的 permissions 资源。每项资源都用于标识特定 typeusergroupdomainanyone)和 roleownerorganizerfileOrganizerwritercommenterreader)的权限。例如,某文件可能具有一项权限,用于授予特定用户 (type=user) 只读访问权限 (role=reader);而另一项权限则用于授予特定群组 (type=group) 的成员向文件添加评论的权限 (role=commenter)。

如需查看角色及其允许的操作的完整列表,请参阅角色和权限

权限的运作方式

文件夹的权限列表会向下传播。所有子文件和子文件夹都会继承父文件夹的权限。每当权限或层次结构发生更改时,系统都会通过所有嵌套文件夹以递归方式进行传播。例如,如果某个文件位于某个文件夹中,而该文件夹随后被移到另一个文件夹中,则新文件夹的权限会传播到该文件。如果新文件夹授予文件用户新角色(例如“写入者”),则会覆盖其旧角色。

反之,如果某个文件从文件夹继承了 role=writer,并被移至提供“读者”角色的另一个文件夹,则该文件现在会继承 role=reader

无法从共享云端硬盘中的文件或文件夹中移除继承的权限。 而必须在直接或间接父级中调整这些权限,因为这些权限是从父级继承的。您可以从“我的云端硬盘”或“与我共享”中的内容移除继承的权限。

相反,在“我的云端硬盘”中的文件或文件夹上,可以替换继承的权限。因此,如果某个文件从“我的云端硬盘”文件夹继承了 role=writer,您可以为该文件设置 role=reader 以降低其权限级别。

了解文件功能

permissions 资源最终不会决定当前用户对文件或文件夹执行操作的能力。相反,files 资源包含一组布尔值 capabilities 字段,用于指示是否可以对文件或文件夹执行操作。Google Drive API 会根据与文件或文件夹关联的当前用户的权限资源设置这些字段。

例如,当 Alex 登录您的应用并尝试共享文件时,系统会检查 Alex 的角色是否具有该文件的权限。如果该角色允许用户共享文件,则与该文件相关的 capabilities(例如 canShare)会根据该角色进行填充。如果 Alex 想要分享该文件,您的应用会检查 capabilities,以确保 canShare 设置为 true

如需查看检索文件 capabilities 的示例,请参阅获取文件权能

获取文件功能

当应用打开文件时,应检查文件的功能,并呈现界面以反映当前用户的权限。例如,如果用户对文件没有 canComment 权限,则应在界面中停用评论功能。

如需检查功能,请针对 files 资源调用 get() 方法,并将 fileId 路径参数和 fields 参数设置为 capabilities 字段。如需详细了解如何使用 fields 参数返回字段,请参阅返回特定字段

以下代码示例展示了如何验证用户权限。响应会返回用户对相应文件拥有的功能列表。每项功能都对应于用户可以采取的精细操作。系统仅会为共享云端硬盘中的内容填充某些字段。

请求

GET https://www.googleapis.com/drive/v3/files/FILE_ID?fields=capabilities

答案

{
  "capabilities": {
    "canAcceptOwnership": false,
    "canAddChildren": false,
    "canAddMyDriveParent": false,
    "canChangeCopyRequiresWriterPermission": true,
    "canChangeItemDownloadRestriction": true,
    "canChangeSecurityUpdateEnabled": false,
    "canChangeViewersCanCopyContent": true,
    "canComment": true,
    "canCopy": true,
    "canDelete": true,
    "canDisableInheritedPermissions": false,
    "canDownload": true,
    "canEdit": true,
    "canEnableInheritedPermissions": true,
    "canListChildren": false,
    "canModifyContent": true,
    "canModifyContentRestriction": true,
    "canModifyEditorContentRestriction": true,
    "canModifyOwnerContentRestriction": true,
    "canModifyLabels": true,
    "canMoveChildrenWithinDrive": false,
    "canMoveItemIntoTeamDrive": true,
    "canMoveItemOutOfDrive": true,
    "canMoveItemWithinDrive": true,
    "canReadLabels": true,
    "canReadRevisions": true,
    "canRemoveChildren": false,
    "canRemoveContentRestriction": false,
    "canRemoveMyDriveParent": true,
    "canRename": true,
    "canShare": true,
    "canTrash": true,
    "canUntrash": true
  }
}

共享云端硬盘资源的使用场景

有五种不同的分享场景:

  1. 如需共享“我的云端硬盘”中的文件,用户必须拥有 role=writerrole=owner

    • 如果将 writersCanShare 布尔值设置为 false,则用户必须拥有 role=owner

    • 如果拥有role=writer权限的用户所拥有的临时访问权限受过期日期和时间的限制,则无法共享相应文件。如需了解详情,请参阅设置过期日期以限制文件访问权限

  2. 如需共享“我的云端硬盘”中的文件夹,用户必须拥有 role=writerrole=owner

    • 如果文件的 writersCanShare 布尔值设置为 false,则用户必须拥有更宽松的 role=owner

    • 对于具有 role=writer 的“我的云端硬盘”文件夹,不允许临时访问(受访问权限到期日期和时间限制)。如需了解详情,请参阅设置过期日期以限制文件访问权限

  3. 如需分享共享云端硬盘中的文件,用户必须拥有 role=writerrole=fileOrganizerrole=organizer 权限。

    • writersCanShare 设置不适用于共享云端硬盘中的内容。 系统会将其视为始终设置为 true
  4. 如需共享共享云端硬盘中的文件夹,用户必须拥有 role=organizer

    • 如果共享云端硬盘的 sharingFoldersRequiresOrganizerPermission 限制设置为 false,则具有 role=fileOrganizer 权限的用户可以共享该共享云端硬盘中的文件夹。
  5. 如需管理共享云端硬盘成员资格,用户必须拥有 role=organizer。只有用户和群组才能成为共享云端硬盘的成员。

创建权限

创建权限时,需要提供以下两个字段:

  • typetype 用于标识权限范围(usergroupdomainanyone)。带有 type=user 的权限适用于特定用户,而带有 type=domain 的权限适用于特定网域中的所有人。

  • rolerole 字段用于标识 type 可以执行的操作。例如,具有 type=userrole=reader 的权限可授予特定用户对文件或文件夹的只读访问权限。或者,具有 type=domainrole=commenter 的权限可让网域中的所有人向文件添加评论。如需查看角色和每种角色允许的操作的完整列表,请参阅角色和权限

创建权限时,如果权限为 type=usertype=group,您还必须提供 emailAddress,以将特定用户或群组与该权限相关联。

创建 type=domain 的权限时,您还必须提供 domain,以将特定网域与权限相关联。

如需创建权限,请执行以下操作:

  1. create() 方法与关联文件或文件夹的 fileId 路径参数搭配使用。
  2. 在请求正文中,指定 typerole
  3. 如果值为 type=usertype=group,请提供 emailAddress。如果为 type=domain,请提供 domain

以下代码示例展示了如何创建权限。响应会返回 Permission 资源的实例,包括分配的 permissionId

请求

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

答案

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

使用目标对象群组

目标对象群组是您可以推荐给用户,供其与之共享内容的用户群组(例如部门或团队)。您可以鼓励用户与特定或部分对象共享内容,而不是与整个组织共享。目标对象群组可帮助您提高数据的安全性与隐私性,并让用户更轻松地选择合适的内容共享对象。如需了解详情,请参阅目标受众群体简介

如需使用目标对象群组,请执行以下操作:

  1. 在 Google 管理控制台中,依次点击“菜单”图标 > 目录 > 目标对象群组

    前往“目标对象群组”

    您必须使用拥有超级用户权限的账号登录,才能执行此任务。

  2. 目标对象群组列表中,点击目标对象群组的名称。如需创建目标对象群组,请参阅创建目标对象群组

  3. 从目标受众群体网址 https://admin.google.com/ac/targetaudiences/ID 中复制唯一 ID。

  4. 使用 type=domain 创建权限,并将 domain 字段设置为 ID.audience.googledomains.com

如需了解用户如何与目标受众群体互动,请参阅链接分享的用户体验

列出所有权限

使用 permissions 资源中的 list() 方法检索文件、文件夹或共享云端硬盘的所有权限。

以下代码示例展示了如何获取所有权限。响应会返回权限列表。

请求

GET https://www.googleapis.com/drive/v3/files/FILE_ID/permissions

答案

{
  "kind": "drive#permissionList",
  "permissions": [
    {
      "id": "PERMISSION_ID",
      "type": "user",
      "kind": "drive#permission",
      "role": "commenter"
    }
  ]
}

更新权限

如需更新文件或文件夹的权限,您可以更改分配的角色。如需详细了解如何查找角色来源,请参阅确定角色来源

  1. permissions 资源调用 update() 方法,并将 permissionId 路径参数设置为要更改的权限,并将 fileId 路径参数设置为关联的文件、文件夹或共享云端硬盘。如需查找 permissionId,请对 permissions 资源使用 fileId 路径参数调用 list() 方法。

  2. 在请求中,标识新的 role

即使相应用户或群组已是共享云端硬盘的成员,您也可以为共享云端硬盘中的单个文件或文件夹授予权限。例如,Alex 拥有 role=commenter,这是其共享云端硬盘成员身份的一部分。不过,您的应用可以为共享云端硬盘中的文件授予 Alex role=writer 权限。在这种情况下,由于新角色的权限比通过成员身份授予的角色的权限更宽松,因此新权限将成为文件或文件夹的有效角色

以下代码示例展示了如何将文件或文件夹的权限从评论者更改为写入者。响应会返回 permissions 资源的实例。

请求

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

答案

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

确定角色来源

如需更改文件或文件夹的角色,您必须知道该角色的来源。 对于共享云端硬盘,角色的来源可能基于共享云端硬盘的成员资格、文件夹的角色或文件的角色。

如需确定共享云端硬盘或该云端硬盘中各项内容的角色来源,请对 permissions 资源调用 get() 方法,并使用 fileIdpermissionId 路径参数,以及设置为 permissionDetails 字段的 fields 参数。

如需查找 permissionId,请对 permissions 资源使用 fileId 路径参数调用 list() 方法。如需提取 list 请求中的 permissionDetails 字段,请将 fields 参数设置为 permissions/permissionDetails

此字段会列出用户、群组或网域的所有继承的文件权限和直接文件权限。

以下代码示例展示了如何确定角色来源。响应会返回 permissions 资源的 permissionDetailsinheritedFrom 字段提供继承权限的内容的 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
    }
  ]
}

通过批量请求更新多项权限

我们强烈建议您使用批量请求来修改多项权限。

以下是使用客户端库执行批量权限修改的示例。

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

删除权限

如需撤消对文件或文件夹的访问权限,请对 permissions 资源调用 delete() 方法,并将 fileIdpermissionId 路径参数设置为删除相应权限。

对于“我的云端硬盘”中的内容,您可以删除继承的权限。删除继承的权限会撤消对相应内容和子内容(如有)的访问权限。

对于共享云端硬盘中的内容,无法撤消继承的权限。请改为更新或删除父文件或文件夹的权限。

delete() 方法还用于删除直接应用于共享云端硬盘文件或文件夹的权限。

以下代码示例展示了如何通过删除 permissionId 来撤消访问权限。如果成功,则响应正文为空。如需确认权限已移除,请对 permissions 资源使用 list() 方法,并提供 fileId 路径参数。

请求

DELETE https://www.googleapis.com/drive/v3/files/FILE_ID/permissions/PERMISSION_ID

设置过期日期以限制文件访问权限

如果您与他人协作处理敏感项目,可能希望在一段时间后限制他们对云端硬盘中特定文件的访问权限。对于“我的云端硬盘”中的文件,您可以设置失效日期,以限制或移除对相应文件的访问权限。

如需设置失效日期,请执行以下操作:

expirationTime 字段使用 RFC 3339 日期时间表示权限的到期时间。到期时间具有以下限制:

  • 只能对用户和群组权限设置失效时间。
  • 时间必须是未来的时间。
  • 时间不能是未来一年以后的时间。

如需详细了解有效期,请参阅以下文章: