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

每个 Google 云端硬盘文件、文件夹和共享云端硬盘都有关联的权限资源。每个资源都会标识特定 type(用户、群组、网域、任何人)和 role(如“commenter”或“Reader”)的权限。例如,文件可能具有向特定用户 (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)将被填充。如果 Alex 想要分享该文件,您的应用会检查 capabilities,以确保 canShare 已设置为 true

创建权限

创建权限时,需要填写以下 2 个字段:

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

  • role - role 字段用于标识 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 方法检索文件、文件夹或共享云端硬盘的所有权限。

验证用户权限

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

如需检查功能,请调用 files.get,并将 fileIdfields 参数设为 capabilities 字段。

如需详细了解如何使用 fields 参数返回字段,请参阅返回文件的特定字段

确定共享云端硬盘文件和文件夹的角色来源

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

如需确定共享云端硬盘或该云端硬盘中内容的角色来源,请调用 permissions.get,并将 fileIdpermissionIdfields 参数设为 permissionDetails 字段。要查找 permissionId,请结合使用 permissions.listfileId

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

更改权限

如需更改对文件或文件夹的权限,您可以更改已分配的角色:

  1. 调用permissions.update具有更改权限的permissionId权限,并为关联的文件、文件夹或共享云端硬盘调用 fileId。要查找 permissionId,请结合使用 permissions.listfileId

  2. 在请求中,确定新的 role

即使用户或群组已经是成员,您也可以授予对共享云端硬盘中个别文件或文件夹的权限。例如,Alex 是共享云端硬盘成员的role=commenter成员。但是,您的应用可以为共享云端硬盘中的文件授予 Alex 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;
        }
    }
}