Google Drive API/SDK TransferOwnership

2019-05-22 11:57发布

问题:

Im trying to transfer the ownership of a specific file to another user.

Total Code

foreach (Permission permission in RetrievePermissions(service(), file.Id))
        {
            if (permission.Role == EnumClass.PERMISSIONROLE.OWNER.ToText())
            {
                //Downgrade Owner Writer
                UpdatePermission(service(), file.Id, permission.Id, EnumClass.PERMISSIONROLE.WRITER);
                //Create New Writer
                InsertPermission(service(), file.Id, ownerMail, EnumClass.PERMISSIONROLE.WRITER);

                foreach (Permission thisPermission in RetrievePermissions(service(), file.Id))
                {   //Update Writer to Owner
                    if (thisPermission.Name == "Person X")
                    {
                        //Set Person X as new Owner
                        UpdatePermission(service(), file.Id, thisPermission.Id, EnumClass.PERMISSIONROLE.OWNER);
                    }
                }
            }
        }

Update Permission Method

public static Permission UpdatePermission(DriveService service, String fileId, String permissionId, EnumClass.PERMISSIONROLE ROLE)
    {
        try
        {
            // First retrieve the permission from the API.
            Permission permission = service.Permissions.Get(fileId, permissionId).Execute();
            permission.Role = ROLE.ToText();

            //if new Role is Owner, Downgrad current Owner
            if (ROLE == EnumClass.PERMISSIONROLE.OWNER)
            {
                var myPermission = service.Permissions.Update(permission, fileId, permissionId);
                myPermission.TransferOwnership = true;

                foreach (Permission per in RetrievePermissions(service, fileId))
                {
                    if (per.Role == EnumClass.PERMISSIONROLE.OWNER.ToText())
                    {
                        per.Role = EnumClass.PERMISSIONROLE.WRITER.ToText();
                    }
                }
            }
            return service.Permissions.Update(permission, fileId, permissionId).Execute();
        }

        catch (Exception e)
        {
            Console.WriteLine("An error occurred: " + e.Message);
        }
        return null;

Insert Permission Method

 public static Permission InsertPermission(DriveService service, String fileId, String userMail, EnumClass.PERMISSIONROLE Role)
    {
        Permission newPermission = new Permission();
        newPermission.Name = userMail;
        newPermission.Value = userMail;
        newPermission.Type = EnumClass.PERMISSIONTYPE.USER.ToText();
        newPermission.Role = Role.ToText();

        try
        {
            return service.Permissions.Insert(newPermission, fileId).Execute();
        }
        catch (Exception InsertError)
        {
            Console.WriteLine("Error inserting permission for " + userMail + Environment.NewLine + "Error on Insert: " + InsertError.Message);
        }
        return null;
    }

Error

Google.Apis.Requests.RequestError Insufficient permissions for this file [403] Errors [ Message[Insufficient permissions for this file] Location[ - ] Reason[forbidden] Domain[global] ]

Im currently using the ServiceAccount.
All help appreciated!

回答1:

Did you try to use impersonation?

var initializer = new ServiceAccountCredential.Initializer(ServiceAccountEmail)
{
    Scopes = new[] { DriveService.Scope.Drive },
    User = "user@yourdomain.com"
};


回答2:

The best way to transfer the ownership is to

  1. Enable domain wide delegation to the service account

  2. Impersonate the user while initialling the drive service as below:

*

 using (var credentialJSON =new FileStream(_settings.CertificatePath,FileMode.Open, FileAccess.Read))
            {
                var credentialParameters =
                    NewtonsoftJsonSerializer.Instance.Deserialize<JsonCredentialParameters>(credentialJSON);

                credential = new ServiceAccountCredential(
                    new ServiceAccountCredential.Initializer(credentialParameters.ClientEmail)
                    {
                        Scopes = scopes,
                        User = ownerEmailAddress, //put in the actual user email address
                    }.FromPrivateKey(credentialParameters.PrivateKey));
            }