Tôi đã tham gia xây dựng một ứng dụng sử dụng nội bộ mà qua đó người dùng có thể tải tệp lên, được lưu trữ trong Google Drive. Vì không nên sử dụng tài khoản dịch vụ làm chủ sở hữu tệp, tôi muốn tải lên ứng dụng thay mặt cho tài khoản người dùng được chỉ định mà công ty sysadmin có quyền truy cập.Thất bại trong việc ủy quyền truy cập Google Drive vào tài khoản dịch vụ
Tôi đã tạo ứng dụng cùng với tài khoản dịch vụ. Có hai phím tạo cho tài khoản dịch vụ, như tôi đã thử cả JSON và các định dạng pkcs12 cố gắng thực hiện điều này:
tôi đã tải OAuth 2.0 chi tiết ID của khách hàng, và cũng có .json và các file đuôi .p12 cho các phím tài khoản dịch vụ (theo thứ tự mà như được hiển thị ở trên):
tôi đã sysadmin của tôi đi qua các bước chi tiết tại đây để uỷ quyền cho truy cập Drive API để tài khoản dịch vụ: https://developers.google.com/drive/v2/web/delegation#delegate_domain-wide_authority_to_your_service_account
Chúng tôi nhận thấy rằng điều duy nhất hoạt động cho "Tên khách hàng" ở bước 4 là "ID ứng dụng khách" được liệt kê cho ứng dụng web (kết thúc .apps.googleusercontent.com). Các ID hexadecimal dài liệt kê cho các phím tài khoản dịch vụ không gì nó yêu cầu (xem dưới đây):
Trước đây đến ở trên, tôi đã có mã số đó sẽ tạo ra một trường hợp DriveService có thể tải trực tiếp lên dịch vụ tài khoản, tham khảo các tập tin .json cho khóa tài khoản dịch vụ:
private DriveService GetServiceA()
{
var settings = SettingsProvider.GetInstance();
string keyFilePath = HostingEnvironment.MapPath("~/App_Data/keyfile.json");
var scopes = new string[] { DriveService.Scope.Drive };
var stream = new IO.FileStream(keyFilePath, IO.FileMode.Open, IO.FileAccess.Read);
var credential = GoogleCredential.FromStream(stream);
credential = credential.CreateScoped(scopes);
var service = new DriveService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "MyAppName"
});
return service;
}
đó làm việc niêm yết và tải lên, mặc dù tất nhiên không có giao diện web để truy cập vào các tập tin, và có vẻ như là mặc dù nó không xử lý những thứ như siêu dữ liệu quyền hoặc tạo hình thu nhỏ cho ví dụ PDF. Đây là lý do tại sao tôi đang cố gắng sử dụng tài khoản chuẩn cho video tải lên. Khi đã được phân loại rõ ràng, sau đó tôi đã cố gắng điều chỉnh mã được hiển thị trong tham chiếu ủy nhiệm được liên kết ở trên, kết hợp với mã từ nơi khác để trích xuất các chi tiết cần thiết từ tệp khóa .json. Với mã này, ngay sau khi tôi cố gắng để thực hiện bất kỳ lệnh API, thậm chí đơn giản như:
FileList fileList = service.FileList().Execute();
tôi nhận được một lỗi:
Ngoại lệ chi tiết: Google.Apis.Auth.OAuth2.Responses.TokenResponseException : Lỗi: "unauthorized_client", mô tả: "client trái phép hoặc phạm vi trong yêu cầu.", Uri: ""
mã cho nỗ lực đó là:
private DriveService GetServiceB()
{
var settings = SettingsProvider.GetInstance();
string keyFilePath = HostingEnvironment.MapPath("~/App_Data/keyfile.json");
string serviceAccountEmail = "<account-email>@<project-id>.iam.gserviceaccount.com";
var scopes = new string[] { DriveService.Scope.Drive };
var stream = new IO.FileStream(keyFilePath, IO.FileMode.Open, IO.FileAccess.Read);
var reader = new IO.StreamReader(stream);
string jsonCreds = reader.ReadToEnd();
var o = JObject.Parse(jsonCreds);
string privateKey = o["private_key"].ToString();
var credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
Scopes = scopes,
User = "[email protected]"
}
.FromPrivateKey(privateKey)
);
var service = new DriveService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "MyAppName"
});
return service;
}
Cuối cùng, tôi đã tạo ra thứ hai se rvice khóa tài khoản để lưu a.tập p12 để phù hợp chặt chẽ hơn các mã trong tài liệu hướng dẫn phái đoàn chính quyền, nhưng mà kết quả trong cùng một ngoại lệ:
private DriveService GetServiceC()
{
var settings = SettingsProvider.GetInstance();
string p12KeyFilePath = HostingEnvironment.MapPath("~/App_Data/keyfile.p12");
string serviceAccountEmail = "<account-email>@<project-id>.iam.gserviceaccount.com";
var scopes = new string[] { DriveService.Scope.Drive }; // Full access
X509Certificate2 certificate = new X509Certificate2(
p12KeyFilePath,
"notasecret",
X509KeyStorageFlags.Exportable
);
var credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
Scopes = scopes,
User = "[email protected]"
}
.FromCertificate(certificate)
);
var service = new DriveService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "MyAppName"
});
return service;
}
Lớp liên quan minimial mà phương pháp này sống là:
public class GoogleDrive
{
public DriveService Service { get; private set; }
public GoogleDrive()
{
this.Service = this.GetService();
}
private DriveService GetService()
{
// Code from either A, B or C
}
public FilesResource.ListRequest FileList()
{
return this.Service.Files.List();
}
}
Và đó là được sử dụng trong thời trang này:
var service = new GoogleDrive();
FilesResource.ListRequest listRequest = service.FileList();
FileList fileList = listRequest.Execute();
Trường hợp ngoại lệ xảy ra trên dòng cuối cùng đó.
Tôi không hiểu tại sao tài khoản dịch vụ của tôi không thể hành động thay mặt cho người dùng được chỉ định, là một phần của tên miền mà tài khoản dịch vụ của ứng dụng phải được ủy quyền. Tôi đã hiểu lầm điều gì ở đây?
Đây có thể là lỗi cấu hình. Bạn đã nhập ID ứng dụng của tài khoản dịch vụ trong tên Khách hàng chưa? Đó là bướC# 5 trong [Ủy quyền toàn quyền miền cho tài khoản dịch vụ của bạn] (https://developers.google.com/drive/v2/web/delegation#delegate_domain-wide_authority_to_your_service_account) – noogui
@noogui Tệp .json được tạo cho khóa tài khoản dịch vụ chứa mục nhập "client_id", là số thập phân gồm 21 chữ số. Sử dụng cho bướC# 5 cho thấy một thông báo lỗi: "Tên khách hàng này chưa được đăng ký với Google." –