google-drive-api - 谷歌选择器 + 谷歌云端硬盘 API
问题描述
作为Project Strobe的一部分,Google 计划将许多 Google Drive API 范围移动到“受限”,这意味着您需要独立的安全验证。
在同一篇文章中,他们建议使用 Google Picker 和 drive.file 范围来获取每个文件的访问权限。我已经成功实现了 Google Picker API 来访问文件并检索文件的元数据。但是,我如何通过此流程实际导入文件的内容(例如,实际 Google 工作表中的数据)?
谷歌选择器包装
import React from "react";
import PropTypes from "prop-types";
import loadScript from "load-script";
const GOOGLE_SDK_URL = "https://apis.google.com/js/api.js";
let scriptLoadingStarted = false;
class GoogleFilePicker extends React.Component {
static propTypes = {
children: PropTypes.node,
clientId: PropTypes.string.isRequired,
developerKey: PropTypes.string,
scope: PropTypes.array,
viewId: PropTypes.string,
authImmediate: PropTypes.bool,
origin: PropTypes.string,
onChange: PropTypes.func,
onAuthenticate: PropTypes.func,
onAuthFailed: PropTypes.func,
createPicker: PropTypes.func,
multiselect: PropTypes.bool,
navHidden: PropTypes.bool,
disabled: PropTypes.bool,
authToken: PropTypes.string,
};
static defaultProps = {
onChange: () => {},
onAuthenticate: () => {},
onAuthFailed: () => {},
scope: ["https://www.googleapis.com/auth/drive.file"],
viewId: "DOCS",
authImmediate: false,
multiselect: false,
navHidden: false,
disabled: false,
authToken: "",
};
constructor(props) {
super(props);
this.onApiLoad = this.onApiLoad.bind(this);
this.onChoose = this.onChoose.bind(this);
}
componentDidMount() {
if (this.isGoogleReady()) {
// google api is already exists
// init immediately
this.onApiLoad();
} else if (!scriptLoadingStarted) {
// load google api and the init
scriptLoadingStarted = true;
loadScript(GOOGLE_SDK_URL, this.onApiLoad);
} else {
// is loading
}
}
isGoogleReady() {
return !!window.gapi;
}
isGoogleAuthReady() {
return !!window.gapi.auth;
}
isGooglePickerReady() {
return !!window.google.picker;
}
onApiLoad() {
window.gapi.load("auth");
window.gapi.load("picker");
}
doAuth(callback) {
window.gapi.auth.authorize(
{
client_id: this.props.clientId,
scope: this.props.scope,
immediate: this.props.authImmediate,
},
callback
);
}
onChoose() {
if (
!this.isGoogleReady() ||
!this.isGoogleAuthReady() ||
!this.isGooglePickerReady() ||
this.props.disabled
) {
return null;
}
// const token = window.gapi.auth.getToken();
// const oauthToken = token && token.access_token;
const oauthToken = this.props.authToken;
if (oauthToken) {
this.createPicker(oauthToken);
} else {
this.doAuth((response) => {
if (response.access_token) {
this.createPicker(response.access_token);
} else {
this.props.onAuthFailed(response);
}
});
}
}
createPicker(oauthToken) {
// this.props.onAuthenticate(oauthToken);
if (this.props.createPicker) {
return this.props.createPicker(window.google, oauthToken);
}
const googleViewId = window.google.picker.ViewId[this.props.viewId];
const view = new window.google.picker.View(googleViewId);
if (this.props.mimeTypes) {
view.setMimeTypes(this.props.mimeTypes.join(","));
}
if (this.props.query) {
view.setQuery(this.props.query);
}
if (!view) {
throw new Error("Can't find view by viewId");
}
const picker = new window.google.picker.PickerBuilder()
.addView(view)
.setOAuthToken(oauthToken)
.setDeveloperKey(this.props.developerKey)
.setCallback(this.props.onChange);
if (this.props.origin) {
picker.setOrigin(this.props.origin);
}
if (this.props.navHidden) {
picker.enableFeature(window.google.picker.Feature.NAV_HIDDEN);
}
if (this.props.multiselect) {
picker.enableFeature(window.google.picker.Feature.MULTISELECT_ENABLED);
}
picker.build().setVisible(true);
}
render() {
console.log(window.gapi);
return (
<div onClick={this.onChoose}>
{this.props.children ? (
this.props.children
) : (
<button>Open google chooser</button>
)}
</div>
);
}
}
export default GoogleFilePicker;
调用包装器
我在下面的代码中调用上面的组件。检索到文档后,我将调用 copyFile 函数。当应用程序创建文档时,此功能按预期工作,但当应用程序外部的用户创建文件时,此功能无法正常工作。我知道 Google 打算将其用于 drive.google.file 范围,但文档暗示使用 Google Picker 应该可以解决此问题。
<GoogleFilePicker
clientId="CLIENT ID"
developerKey="DEVELOPER KEY"
scope={["https://www.googleapis.com/auth/drive.file"]}
onChange={(data) => {
if (data.docs) {
copyFile(data.docs[0].id, `Template: ${data.docs[0].name}`, "");
}
}}
onAuthenticate={(token) => console.log("oauth token:", token)}
onAuthFailed={(data) => console.log("on auth failed:", data)}
multiselect={true}
navHidden={true}
authImmediate={false}
// mimeTypes={["image/png", "image/jpeg", "image/jpg"]}
viewId={"DOCS"}
authToken={auth.state.user.googleToken}
>
解决方案
我最近遇到了这个问题,我需要从谷歌云控制台获取应用程序 ID,并将其添加到带有.setAppId(ID_HERE)
. 这设置了它,以便 Google 可以设置应用程序和文件链接,然后当您使用该应用程序进行 API 调用时,它会知道它可以访问该文件。您应该能够在云控制台的同一项目中进行任何 API 请求设置;对我来说,我在同一个项目中启用了 Google Drive、Docs 和 Picker API。我使用选择器允许用户授予对模板文件的应用程序的访问权限,然后应用程序可以将该模板复制到用户驱动器,然后使用 Doc API 将他们的数据注入其中。
您可能还需要设置一个回调函数以在用户进行选择/取消选择器后执行。例如,我是这样实现的:
var self = this;
var filePickerCallback = (data) => {
if (data[google.picker.Response.ACTION] == google.picker.Action.PICKED) {
var doc = data[google.picker.Response.DOCUMENTS][0];
if (doc["id"] === getTemplateToFindInPicker()){
self.startGoogleDocumentBuild();
} else {
self.showDocsDialog_(ERROR, WRONG FILE SELECTED);
}
}
if(data[google.picker.Response.ACTION] == google.picker.Action.CANCEL){
self.showPickerFlowErrorDialog();
}
}
filePickerCallback.bind(this);
let token = getPickerAccessToken();
var isMCAV = CODE_TO_CHECK_MCAVNESS;
let name = NAME_BASED_ON_CONTEXT;
// let's us choose the query string, what to search based on file name, so its very clear what the user needs to choose
let view = new google.picker.View(google.picker.ViewId.DOCUMENTS).setQuery(name);
var picker = new google.picker.PickerBuilder()
.addView(view)
.setTitle("Please choose: " + name)
.setAppId(getAppIDs())
.setOAuthToken(token)
.setDeveloperKey(getDeveloperKey())
.setCallback(filePickerCallback)
.build();
picker.setVisible(true);
推荐阅读
- python - 在 azure 函数上发布时无法运行 blob 触发器
- dax - 为什么在日期轴中返回“(空白)”值?
- javascript - 通过node从Mysql数据库中获取数据,然后在typescript中访问
- c# - 如何使用可为空的类型引用或如何在 .NET Core 的预览中启用它
- java - 如何连续触发或发送意图(无需单击按钮)
- php - 如何在php中逐行分隔html标签?
- python - 绘制箱线图关闭异常值检测
- regex - 动态 htaccess 重写规则
- gremlin - 得到另一个查询的响应后如何执行查询?
- react-native - 通过样式将矩形视图变为四边形视图 - react native