파일, 폴더, 드라이브 공유

모든 Google Drive 파일, 폴더, 공유 드라이브에는 연결된 권한 리소스가 있습니다. 각 리소스는 '댓글 작성자' 또는 '리더'와 같은 특정 type(사용자, 그룹, 도메인, 모든 사용자) 및 role의 권한을 식별합니다. 예를 들어 파일에는 특정 사용자 (type=user)에게 읽기 전용 액세스 권한(role=reader)을 부여하는 권한이 있고, 다른 권한은 특정 그룹 구성원(type=group)에게 파일에 댓글을 추가할 수 있는 권한 (role=commenter)을 부여할 수 있습니다.

전체 역할 및 각 역할이 허용하는 작업은 역할을 참조하세요.

Drive 리소스 공유 시나리오

공유 시나리오에는 5가지 유형이 있습니다.

  1. 내 드라이브에서 파일을 공유하려면 사용자에게 '작성자' 이상의 역할이 있어야 합니다.

    • 파일의 writersCanShare 부울 값이 False로 설정되어 있으면 사용자에게 '소유자' 역할이 있어야 합니다.

    • '작성자' 역할의 사용자가 만료일 및 시간이 적용되는 임시 액세스 권한을 보유하는 경우 파일을 공유할 수 없습니다.

    자세한 내용은 만료일 추가를 참고하세요.

  2. 내 드라이브에서 폴더를 공유하려면 사용자에게 '작성자' 이상의 역할이 있어야 합니다.

    • 파일의 writersCanShare부울 값이 False로 설정되면 사용자에게 더 많은 권한이 있는 '소유자' 역할이 있어야 합니다.

    • 내 드라이브 폴더에서 '작성자' 역할이 있는 임시 액세스 (만료일 및 시간 적용)는 허용되지 않습니다.

  3. 공유 드라이브의 파일을 공유하려면 사용자에게 '작성자' 이상의 역할이 있어야 합니다.

    • 공유 드라이브의 항목에는 writersCanShare 설정이 적용되지 않습니다. 마치 항상 True로 설정된 것처럼 처리됩니다.

    • 만료일 및 시간이 적용되는 임시 액세스는 공유 드라이브에서 허용되지 않습니다.

  4. 공유 드라이브의 폴더를 공유하려면 사용자에게 '주최자' 역할이 있어야 합니다.

  5. 공유 드라이브 멤버십을 관리하려면 사용자에게 '주최자' 역할이 있어야 합니다. 사용자 및 그룹만 공유 드라이브의 멤버가 될 수 있습니다.

권한 전파

폴더의 권한 목록은 아래쪽으로 전파되며 모든 하위 파일과 폴더는 상위 항목의 권한을 상속합니다. 권한 또는 계층 구조가 변경될 때마다 모든 중첩된 폴더를 통해 재귀적으로 전파됩니다. 예를 들어 파일이 폴더에 있고 해당 폴더를 다른 폴더로 이동하면 새 폴더의 권한이 파일에 전파됩니다. 새 폴더가 파일 사용자에게 새로운 역할(예: '작성자')을 부여하면 이전 역할이 재정의됩니다.

반대로 파일이 폴더에서 '작성자' 역할을 상속하고 '리더' 역할을 제공하는 다른 폴더로 이동하면 이제 파일이 '리더' 역할을 상속합니다.

상속된 권한은 공유 드라이브의 파일 또는 폴더에서 삭제할 수 없습니다. 대신, 권한을 상속받은 직접 또는 간접 상위 항목에서 이러한 권한을 조정해야 합니다. 상속된 권한은 '내 드라이브' 또는 '공유 문서함' 아래의 항목에서 삭제할 수 있습니다.

반대로 상속된 권한은 내 드라이브의 파일 또는 폴더에서 재정의할 수 있습니다. 따라서 파일이 내 드라이브 폴더에서 '작성자' 역할을 상속하는 경우 파일에서 '리더' 역할을 설정하여 권한 수준을 낮출 수 있습니다.

기능

권한 리소스는 최종적으로 현재 사용자가 파일 또는 폴더에서 작업을 실행할 수 있는지 여부를 결정하지 않습니다. 대신 Files 리소스에는 파일 또는 폴더에서 작업을 실행할 수 있는지 여부를 나타내는 데 사용되는 부울 capabilities 필드 컬렉션이 포함됩니다. Google Drive API는 파일 또는 폴더와 연결된 현재 사용자의 권한 리소스를 기반으로 이러한 필드를 설정합니다.

예를 들어 알렉스가 앱에 로그인하여 파일을 공유하려고 하면 파일에 관한 권한 측면에서 알렉스의 역할이 확인됩니다. 이 역할로 파일을 공유할 수 있는 경우 파일과 관련된 capabilities(예: canShare)이 역할을 기준으로 채워집니다. Alex가 파일을 공유하고자 한다면 앱은 capabilities를 확인하여 canSharetrue로 설정되어 있는지 확인합니다.

권한 만들기

권한을 만들 때 다음 두 가지 필드가 필요합니다.

  • type: type는 권한의 범위 (user, group, domain 또는 anyone)를 식별합니다. type=user의 권한은 특정 사용자에게 적용되는 반면 type=domain의 권한은 특정 도메인의 모든 사용자에게 적용됩니다.

  • role - role 필드는 type에서 실행할 수 있는 작업을 나타냅니다. 예를 들어 type=userrole=reader가 있는 권한은 특정 사용자에게 파일 또는 폴더에 대한 읽기 전용 액세스 권한을 부여합니다. 또는 type=domainrole=commenter 권한이 있으면 도메인의 모든 사용자가 파일에 댓글을 추가할 수 있습니다. 전체 역할 및 각 역할이 허용하는 작업은 역할을 참조하세요.

type=user 또는 type=group인 권한을 만들 때는 특정 사용자 또는 그룹을 권한에 연결하기 위해 emailAddress도 제공해야 합니다.

type=domain의 권한을 만들 때 domain도 제공하여 특정 도메인을 권한에 연결해야 합니다.

권한을 만들려면 다음 안내를 따르세요.

  1. permissions.create 메서드를 연결된 파일 또는 폴더의 fileId와 함께 사용합니다.
  2. 요청 본문에서 typerole를 식별합니다.
  3. type=user 또는 type=group이면 emailAddress를 제공합니다. type=domain이면 domain를 제공합니다.

파일, 폴더 또는 공유 드라이브의 모든 권한 가져오기

permissions.list 메서드를 사용하여 파일, 폴더 또는 공유 드라이브의 모든 권한을 검색합니다.

사용자 권한 확인

앱에서 파일을 열면 파일의 기능을 확인하고 UI를 렌더링하여 현재 사용자의 권한을 반영해야 합니다. 예를 들어 사용자에게 파일에 대한 canComment 기능이 없으면 UI에서 댓글을 작성하는 기능을 사용 중지해야 합니다.

기능을 확인하려면 fileIdfields 매개변수를 capabilities 필드로 설정하여 files.get를 호출합니다.

fields 매개변수를 사용하여 필드를 반환하는 방법에 관한 자세한 내용은 파일의 특정 필드 반환을 참고하세요.

공유 드라이브 파일 및 폴더의 역할 소스 확인

파일 또는 폴더의 역할을 변경하려면 역할의 출처를 알아야 합니다. 공유 드라이브의 경우 역할 출처는 공유 드라이브 멤버십, 폴더 역할 또는 파일 역할을 기반으로 할 수 있습니다.

공유 드라이브 또는 드라이브 내의 항목에 대한 역할의 소스를 확인하려면 fileId, permissionId, fields 매개변수를 permissionDetails 필드로 설정하여 permissions.get를 호출합니다. permissionId를 찾으려면 fileId와 함께 permissions.list를 사용합니다.

이 필드는 사용자, 그룹 또는 도메인의 상속된 모든 파일 권한과 직접 파일 권한을 열거합니다.

권한 변경

파일 또는 폴더의 권한을 변경하려면 할당된 역할을 변경하면 됩니다.

  1. 변경할 수 있는 권한의 permissionId와 연결된 파일, 폴더 또는 공유 드라이브의 fileId를 사용하여 permissions.update를 호출합니다. permissionId를 찾으려면 fileId와 함께 permissions.list를 사용합니다.

  2. 요청에서 새 role를 식별합니다.

사용자 또는 그룹이 이미 멤버인 경우에도 공유 드라이브의 개별 파일 또는 폴더에 권한을 부여할 수 있습니다. 예를 들어 Alex는 공유 드라이브 멤버십의 일부로 commenter 역할을 합니다. 하지만 앱은 공유 드라이브에 있는 파일에 관한 writer 역할을 알렉스에게 부여할 수 있습니다. 이 경우 새 역할이 멤버십을 통해 부여된 역할보다 더 관대하기 때문에 새 권한이 파일 또는 폴더의 유효 역할이 됩니다.

파일 또는 폴더에 대한 액세스 권한 취소

파일 또는 폴더에 대한 액세스 권한을 취소하려면 fileIdpermissionId를 사용하여 delete를 호출하여 권한을 삭제합니다.

'내 드라이브' 항목의 경우 상속된 권한을 삭제할 수 있습니다. 상속된 권한을 삭제하면 항목 및 하위 항목(있는 경우)에 대한 액세스 권한이 취소됩니다.

공유 드라이브에 있는 항목의 경우 상속된 권한을 취소할 수 없습니다. 대신 상위 파일 또는 폴더의 권한을 업데이트하거나 취소하세요.

delete 작업은 공유 드라이브 파일 또는 폴더에 직접 적용된 권한을 삭제하는 데도 사용됩니다.

파일 소유권을 동일한 조직의 다른 Google Workspace 계정으로 이전하기

'내 드라이브'에 있는 파일의 소유권을 한 Google Workspace 계정에서 동일한 조직의 다른 계정으로 이전할 수 있습니다. 공유 드라이브를 소유한 조직은 그 안에 있는 파일을 소유합니다. 따라서 공유 드라이브의 파일 및 폴더에 대한 소유권 이전은 지원되지 않습니다. 공유 드라이브의 주최자는 공유 드라이브의 항목을 자신의 '내 드라이브'로 이동하여 소유권을 이전할 수 있습니다.

'내 드라이브'의 파일 소유권을 이전하려면 다음 중 하나를 실행하세요.

  • 특정 사용자(type=user) 소유자 액세스 권한(role=owner)을 부여하는 파일 권한을 만듭니다.

  • owner 역할을 사용하여 기존 파일의 권한을 업데이트하고 소유권을 지정된 사용자(transferOwnership=true)에게 이전합니다.

한 일반 계정에서 다른 일반 계정으로 파일 소유권 이전

파일 소유권을 한 일반 계정에서 다른 일반 계정으로 이전할 수 있습니다. 하지만 Drive는 잠재적 신규 소유자가 이전에 명시적으로 동의할 때까지 2개의 일반 계정 간에 파일 소유권을 이전하지 않습니다. 한 일반 계정에서 다른 일반 계정으로 파일 소유권을 이전하려면 다음 안내를 따르세요.

  1. 현재 소유자는 새로운 새 소유자의 파일 권한을 만들거나 업데이트하여 소유권 이전을 시작합니다. 권한에는 role=writer, type=user, pendingOwner=true 설정이 포함되어야 합니다. 새 소유자가 예비 소유자의 권한을 만드는 경우 예비 새 소유자에게 파일의 소유권을 주장할 것인지 묻는 이메일 알림이 전송됩니다.

  2. 새 소유자는 파일 권한을 만들거나 업데이트하여 소유권 이전 요청을 수락합니다. 권한에는 role=ownertransferOwnership=true 설정이 포함되어야 합니다. 새 소유자가 새 권한을 만들면 소유권이 이전되었음을 알리는 이메일 알림이 이전 소유자에게 전송됩니다.

파일이 이전되면 이전 소유자의 역할이 writer로 다운그레이드됩니다.

일괄 요청으로 여러 권한 변경하기

일괄 요청을 사용하여 여러 권한을 수정하는 것이 좋습니다.

다음은 클라이언트 라이브러리를 사용하여 일괄 권한 수정을 수행하는 예입니다.

자바

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-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_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;
        }
    }
}