【问题标题】:Request specific file permissions with Google Sheets / Google Drive API使用 Google 表格/Google Drive API 请求特定文件权限
【发布时间】:2018-10-24 11:28:54
【问题描述】:

我正在使用 Google 表格 API 来获取 Java 项目的表格数据。一切都按预期在本地工作,但我使用的是详细权限范围https://www.googleapis.com/auth/spreadsheets,它“允许对用户的工作表及其属性进行读/写访问。”。我不想让这个应用程序访问我的 Google Drive 中的所有电子表格(只是暂时在本地这样做)。

理想情况下,我想请求使用文件 ID 对文件进行读/写访问的权限。这可能吗?

如果不可能,我猜https://www.googleapis.com/auth/drive.file 范围提供“对应用程序创建或打开的文件的按文件访问”。是我能得到的最接近的。我还没有找到用这个应用程序打开文件的方法。我该怎么做呢?

或者,如果上述两种解决方案都不理想或不可行,请告诉我您的建议。

谢谢!

【问题讨论】:

  • 丹尼尔,你发现了吗?我想我必须创建一个新的谷歌用户,该用户只能访问我的特定项目的文件。
  • @Matt 我按照您的想法做了同样的事情,并为驱动器文件创建了一个新的 Google 帐户。绝对是最简单和最没有问题的路线。您可能可以通过某种方式使用 Picker API 来完成此操作,但我认为这不值得:developers.google.com/picker/docs

标签: java google-sheets google-api google-drive-api google-sheets-api


【解决方案1】:

我知道这是很久以前发布的,但我会给出答案以帮助将来遇到此问题的未来开发人员。

我认为使用服务帐户可以为您提供所需的功能。服务帐户有点像“机器人”用户,用户可以与之共享文档,然后您的服务器可以登录到此服务帐户以访问这些文档。您可以让他们手动与您共享文档,而不必请求访问用户的整个谷歌驱动器或谷歌表格,我认为这对大多数用户来说会更舒服。

Here is an example 了解如何在 Node.js 中进行设置,但这些想法应该很容易转化为 Java。

【讨论】:

    【解决方案2】:

    范围授予您跨 api 的访问权限,无法将其限制为单个文件或文件组。

    Google Sheets API,v4 范围

    没有办法限制单个文件的权限。假设您正在编辑的文件是由您的应用程序创建的,那么 https://www.googleapis.com/auth/drive.file 应该是一个有效的选项

    示例

    Java quickstart

    import com.google.api.client.auth.oauth2.Credential;
    import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp;
    import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver;
    import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
    import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;
    import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
    import com.google.api.client.http.javanet.NetHttpTransport;
    import com.google.api.client.json.JsonFactory;
    import com.google.api.client.json.jackson2.JacksonFactory;
    import com.google.api.client.util.store.FileDataStoreFactory;
    import com.google.api.services.sheets.v4.Sheets;
    import com.google.api.services.sheets.v4.SheetsScopes;
    import com.google.api.services.sheets.v4.model.ValueRange;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.security.GeneralSecurityException;
    import java.util.Collections;
    import java.util.List;
    
    public class SheetsQuickstart {
        private static final String APPLICATION_NAME = "Google Sheets API Java Quickstart";
        private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
        private static final String TOKENS_DIRECTORY_PATH = "tokens";
    
        /**
         * Global instance of the scopes required by this quickstart.
         * If modifying these scopes, delete your previously saved tokens/ folder.
         */
        private static final List<String> SCOPES = Collections.singletonList(SheetsScopes.SPREADSHEETS_READONLY);
        private static final String CREDENTIALS_FILE_PATH = "/credentials.json";
    
        /**
         * Creates an authorized Credential object.
         * @param HTTP_TRANSPORT The network HTTP Transport.
         * @return An authorized Credential object.
         * @throws IOException If the credentials.json file cannot be found.
         */
        private static Credential getCredentials(final NetHttpTransport HTTP_TRANSPORT) throws IOException {
            // Load client secrets.
            InputStream in = SheetsQuickstart.class.getResourceAsStream(CREDENTIALS_FILE_PATH);
            GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in));
    
            // Build flow and trigger user authorization request.
            GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
                    HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES)
                    .setDataStoreFactory(new FileDataStoreFactory(new java.io.File(TOKENS_DIRECTORY_PATH)))
                    .setAccessType("offline")
                    .build();
            LocalServerReceiver receier = new LocalServerReceiver.Builder().setPort(8888).build();
            return new AuthorizationCodeInstalledApp(flow, receier).authorize("user");
        }
    
        /**
         * Prints the names and majors of students in a sample spreadsheet:
         * https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/edit
         */
        public static void main(String... args) throws IOException, GeneralSecurityException {
            // Build a new authorized API client service.
            final NetHttpTransport HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
            final String spreadsheetId = "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms";
            final String range = "Class Data!A2:E";
            Sheets service = new Sheets.Builder(HTTP_TRANSPORT, JSON_FACTORY, getCredentials(HTTP_TRANSPORT))
                    .setApplicationName(APPLICATION_NAME)
                    .build();
            ValueRange response = service.spreadsheets().values()
                    .get(spreadsheetId, range)
                    .execute();
            List<List<Object>> values = response.getValues();
            if (values == null || values.isEmpty()) {
                System.out.println("No data found.");
            } else {
                System.out.println("Name, Major");
                for (List row : values) {
                    // Print columns A and E, which correspond to indices 0 and 4.
                    System.out.printf("%s, %s\n", row.get(0), row.get(4));
                }
            }
        }
    }
    

    2020 年更新

    有一种方法可以授予每个文件的访问权限。

    https://www.googleapis.com/auth/drive.file 按文件访问应用程序创建或打开的文件。文件授权是按用户授予的,并在用户取消对应用的授权时撤销。

    【讨论】:

    • 非常感谢您的回复。是否有关于如何请求从 Sheets/Drive API 打开文件的文档?
    • 这里有一个示例developers.google.com/sheets/api/quickstart/java 只记得更改范围。您可能还需要获取 google drive api 以获取驱动器范围。 SheetsScopes.DRIVE_FILE 可能会起作用
    • 再次感谢您的回复。有关打开文件(或请求打开文件)的任何文档?该快速入门指南(据我所知)仅显示如何阅读。当使用 DRIVE_FILE 范围尝试通过 ID 读取/请求文件时,我收到 404 错误:{ "code" : 404, "errors" : [ { "domain" : "global", "message" : "Requested entity was not found.", "reason" : "notFound" } ], "message" : "Requested entity was not found.", "status" : "NOT_FOUND" }
    • 这是一个 API。这就是它的作用。它不会为您打开 Google 表格。 Google 表格 API 可让您访问表格中包含的数据。 Google Drive api 让您可以下载文件。没有什么可以为您打开文件。您可能需要 import com.google.api.services.drive.v3.DriveScopes;
    • 嘿丹尼尔!你设法度过了这个难关吗?我正在尝试了解如何减少所要求的范围并做你想做的事情:) 事情是我需要访问其他用户(应用程序是分布式的)
    【解决方案3】:

    我想,这就是你所要求的。 (https://developers.google.com/sheets/api/quickstart/java,https://www.youtube.com/watch?v=zDxTSUWaZs4) 我正在使用此代码通过 ID 访问 Google 表格

    public class ConnectToDatabase extends AsyncTask<Object, Integer, Long> {
    
        private static final String APPLICATION_NAME = "Google Sheets API Java Quickstart";
        private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
        private static final String TOKENS_DIRECTORY_PATH = "tokens";
        private static String SPREADSHEET_ID = INSERTYOURIDHERE;
        private static MainActivity main_Activity = null;
        /**
         * Global instance of the scopes required by this quickstart.
         * If modifying these scopes, delete your previously saved tokens/ folder.
         */
        private static final List<String> SCOPES = Collections.singletonList(SheetsScopes.SPREADSHEETS_READONLY);
        private static final String CREDENTIALS_FILE_PATH = "credentials.json";
    
    
        public ConnectToDatabase(MainActivity mainActivity) {
            this.main_Activity = mainActivity;
        }
    
        private static Credential getCredentials(final NetHttpTransport HTTP_TRANSPORT) throws IOException {
    
            // Load client secrets.
            InputStream in =
                    main_Activity.getAssets().open("credentials.json");
            //new FileInputStream(CREDENTIALS_FILE_PATH);
            ConnectToDatabase.class.getResourceAsStream(CREDENTIALS_FILE_PATH);
            GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in));
    
    
            // Build flow and trigger user authorization request.
    
            GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
                    HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES)
                    .setDataStoreFactory(new FileDataStoreFactory(main_Activity.getDir(TOKENS_DIRECTORY_PATH, Context.MODE_APPEND)))
                    .setAccessType("offline")
                    .build();
    
    
            AuthorizationCodeInstalledApp ab = new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()){
                protected void onAuthorization(AuthorizationCodeRequestUrl authorizationUrl) throws IOException {
                    String url = (authorizationUrl.build());
                            /*flow.newAuthorizationUrl()
                            .setScopes(flow.getScopes())
                            .setAccessType("offline")
                            .setClientId(clientSecrets.getDetails().getClientId())
                            .setRedirectUri("/oauth2-callback")
                            .toString();
    */
    
                    Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
                    main_Activity.startActivity(browserIntent);
                }
            };
            Credential a = ab.authorize("user");
    
    
            return a;
        }
    
        /**
         * Prints the names and majors of students in a sample spreadsheet:
         * https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/edit
         */
        public static void main(String[] args) throws IOException, GeneralSecurityException {
        // Build a new authorized API client service.
                final NetHttpTransport HTTP_TRANSPORT = new com.google.api.client.http.javanet.NetHttpTransport();
                final String range = "A1:H";
                Sheets service = null;
                try {
                    service = new Sheets.Builder(HTTP_TRANSPORT, JSON_FACTORY, getCredentials(HTTP_TRANSPORT))
                            .setApplicationName(APPLICATION_NAME)
                            .build();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                ValueRange response = null;
    
                try {
                    response = service.spreadsheets().values()
                            .get(SPREADSHEET_ID, range)
                            .execute();
                } catch (IOException e) {
                    e.printStackTrace();
                }
    
                List<List<Object>> values = response.getValues();
                [...]
        }
    }
    

    您可能需要根据需要稍微修改此代码 sn-p。我将它用作我的应用程序的一部分。

    那么这段代码会做什么呢? 执行时,此代码将使用您的个人 API 密钥(我将其命名为 credentials.json)连接到 google。 (创建您自己的地址:https://developers.google.com/+/web/api/rest/oauth) 成功验证后,您将能够访问具有特定 ID 的 google sheet。

    【讨论】:

    • 感谢您的回复。不幸的是,由于它使用 SheetsScopes.SPREADSHEETS_READONLY,它仍然提供对我所有 Drive 工作表的读取访问权限。非常感谢您的回复,谢谢。
    猜你喜欢
    • 1970-01-01
    • 2014-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-20
    • 1970-01-01
    • 2016-09-02
    相关资源
    最近更新 更多