使用 JavaScript 授权 Google Drive
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10330992/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Authorization of Google Drive using JavaScript
提问by David
I'm trying to authorize my application to integrate with Google Drive. Google documentation provides details for server based authorization and code samples for various server technologies.
我正在尝试授权我的应用程序与 Google Drive 集成。Google 文档提供了有关各种服务器技术的基于服务器的授权和代码示例的详细信息。
There's also a JavaScript Google API library, that has support for authorization. Down in the samples section of the wikithere is a code snippet for creating a config and calling the authorize function. I've altered the scope to be that one I believe is required for drive:
还有一个支持授权的JavaScript Google API 库。在wiki的示例部分,有一个用于创建配置和调用授权函数的代码片段。我已将范围更改为我认为驱动所需的范围:
var config = {
'client_id': 'my_client_ID',
'scope': 'https://www.googleapis.com/auth/drive.file'
};
gapi.auth.authorize(config, function() {
console.log(gapi.auth);
});
The callback function is never called (yes, the Google API library is loaded corrected) Looking the Java Retrieve and Use OAuth 2.0 Credentials example, the client secret seems to be a parameter, should this go into the config?
回调函数永远不会被调用(是的,谷歌 API 库已加载更正)查看 Java 检索和使用 OAuth 2.0 凭据示例,客户端机密似乎是一个参数,这应该进入配置吗?
Has anyone tried this in JS, for Drive or other Google APIs? Does anyone know the best route for debugging such a problem, i.e. do I need to just step through the library and stop whinging?
有没有人在 JS、Drive 或其他 Google API 中尝试过这个?有谁知道调试此类问题的最佳途径,即我是否需要单步执行库并停止抱怨?
Please don't suggest doing the authorization on the server side, our application is entirely client side, I don't want any state on the server (and I understand the token refresh issues this will cause). I am familiar with the API configuration in the Google console and I believe that and the drive SDK setting are correct.
请不要建议在服务器端进行授权,我们的应用程序完全是客户端,我不希望服务器上有任何状态(我理解这将导致令牌刷新问题)。我熟悉 Google 控制台中的 API 配置,我相信这和驱动器 SDK 设置是正确的。
回答by Nicolas Garnier
It is possible to use the Google APIs Javascript client library with Drive but you have to be aware that there are some pain points.
可以将 Google APIs Javascript 客户端库与 Drive 一起使用,但您必须意识到存在一些痛点。
There are 2 main issues currently, both of which have workarrounds:
目前有两个主要问题,它们都有解决方法:
Authorization
授权
First if you have a look closely at how Google Drive auth works you will realize that, after a user has installed your Drive application and tries to open a file or create a new file with your application, Drive initiates the OAuth 2.0 authorization flow automatically and the auth parameters are set to response_type=codeand access_type=offline. This basically means that right now Drive apps are forced to use the OAuth 2 server-side flow which is not going to be of any use to the Javascript client library (which only uses the client-side flow).
首先,如果您仔细查看 Google Drive 身份验证的工作原理,您会发现,在用户安装您的 Drive 应用程序并尝试使用您的应用程序打开文件或创建新文件后,Drive 会自动启动 OAuth 2.0 授权流程,并且auth 参数设置为response_type=code和access_type=offline。这基本上意味着现在 Drive 应用程序被迫使用 OAuth 2 服务器端流程,这对 Javascript 客户端库(仅使用客户端流程)没有任何用处。
The issue is that: Drive initiates a server-side OAuth 2.0 flow, then the Javascript client library initiates a client-side OAuth 2.0 flow.
问题在于:Drive 启动服务器端 OAuth 2.0 流程,然后 Javascript 客户端库启动客户端 OAuth 2.0 流程。
This can still work, all you have to do it is use server-side code to process the authorization code returned after the Drive server-side flow (you need to exchange it for an access token and a refresh token). That way, only on the first flow will the user be prompted for authorization. After the first time you exchange the authorization code, the auth page will be bypassed automatically.
这仍然可以工作,您所要做的就是使用服务器端代码处理 Drive 服务器端流程之后返回的授权代码(您需要将其交换为访问令牌和刷新令牌)。这样,只有在第一个流中才会提示用户进行授权。第一次交换授权码后,会自动绕过认证页面。
Server side samples to do this is available in our documentation.
If you don't process/exchange the auth code on the server-side flow, the user will be prompted for auth every single time he tries to use your app from Drive.
如果您不在服务器端流程中处理/交换身份验证代码,则用户每次尝试从 Drive 使用您的应用程序时都会被提示进行身份验证。
Handling file content
处理文件内容
The second issue is that uploading and accessing the actual Drive file content is not made easy by our Javascript client library. You can still do it but you will have to use custom Javascript code.
第二个问题是我们的 Javascript 客户端库无法轻松上传和访问实际的 Drive 文件内容。您仍然可以这样做,但您必须使用自定义 Javascript 代码。
Reading the file content
读取文件内容
When a file metadata/a file object is retrieved, it contains a downloadUrl
attribute which points to the actual file content. It is now possible to download the file using a CORS request and the simplest way to auth is to use the OAuth 2 access token in a URL param. So just append &access_token=...
to the downloadUrl
and fetch the file using XHR or by forwarding the user to the URL.
当检索文件元数据/文件对象时,它包含一个downloadUrl
指向实际文件内容的属性。现在可以使用 CORS 请求下载文件,最简单的身份验证方法是在 URL 参数中使用 OAuth 2 访问令牌。因此,只需使用 XHR 或通过将用户转发到 URL附加&access_token=...
到downloadUrl
并获取文件。
Uploading file content
上传文件内容
UPDATE UPDATE: The upload endpoints donow support CORS.
更新来更新:上传端点做现在支持CORS。
~~UPDATE: The upload endpoints, unlike the rest of the Drive API do not support CORS so you'll have to use the trick below for now:~~
~~更新:上传端点与 Drive API 的其余部分不同,不支持 CORS,因此您现在必须使用以下技巧:~~
Uploading a file is tricky because it's not built-in the Javascript client lib and you can't entirely do it with HTTP as described in this responsebecause we don't allow cross-domain requests on these API endpoints. So you do have to take advantage of the iframe proxy used by our Javascript client library and use it to send a constructed multipart request to the Drive SDK. Thanks to @Alain, we have an sample of how to do that below:
上传文件很棘手,因为它不是内置在 Javascript 客户端库中的,而且您不能完全按照本响应中的描述使用 HTTP 来完成,因为我们不允许在这些 API 端点上进行跨域请求。因此,您必须利用我们的 Javascript 客户端库使用的 iframe 代理,并使用它向 Drive SDK 发送构建的多部分请求。感谢@Alain,我们在下面提供了如何执行此操作的示例:
/**
* Insert new file.
*
* @param {File} fileData File object to read data from.
* @param {Function} callback Callback function to call when the request is complete.
*/
function insertFileData(fileData, callback) {
const boundary = '-------314159265358979323846';
const delimiter = "\r\n--" + boundary + "\r\n";
const close_delim = "\r\n--" + boundary + "--";
var reader = new FileReader();
reader.readAsBinaryString(fileData);
reader.onload = function(e) {
var contentType = fileData.type || 'application/octet-stream';
var metadata = {
'title': fileData.fileName,
'mimeType': contentType
};
var base64Data = btoa(reader.result);
var multipartRequestBody =
delimiter +
'Content-Type: application/json\r\n\r\n' +
JSON.stringify(metadata) +
delimiter +
'Content-Type: ' + contentType + '\r\n' +
'Content-Transfer-Encoding: base64\r\n' +
'\r\n' +
base64Data +
close_delim;
var request = gapi.client.request({
'path': '/upload/drive/v2/files',
'method': 'POST',
'params': {'uploadType': 'multipart'},
'headers': {
'Content-Type': 'multipart/mixed; boundary="' + boundary + '"'
},
'body': multipartRequestBody});
if (!callback) {
callback = function(file) {
console.log(file)
};
}
request.execute(callback);
}
}
To improve all this, in the future we might:
为了改善这一切,未来我们可能会:
- Let developers choose which OAuth 2.0 flow they want to use (server-side or client-side) or let the developer handle the OAuth flow entirely.
- Allow CORS on the
/upload/...
endpoints - Allow CORS on the
exportLinks
for native gDocs - We should make it easier to upload files using our Javascript client library.
- 让开发人员选择他们想要使用的 OAuth 2.0 流程(服务器端或客户端),或者让开发人员完全处理 OAuth 流程。
- 允许
/upload/...
端点上的 CORS - 允许
exportLinks
本地 gDocs上的 CORS - 我们应该使用我们的 Javascript 客户端库更容易上传文件。
No promises at this point though :)
不过目前没有承诺:)
回答by InsaurraldeAP
I did it. Heres my code:
我做到了。这是我的代码:
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8' />
<style>
p {
font-family: Tahoma;
}
</style>
</head>
<body>
<!--Add a button for the user to click to initiate auth sequence -->
<button id="authorize-button" style="visibility: hidden">Authorize</button>
<script type="text/javascript">
var clientId = '######';
var apiKey = 'aaaaaaaaaaaaaaaaaaa';
// To enter one or more authentication scopes, refer to the documentation for the API.
var scopes = 'https://www.googleapis.com/auth/drive';
// Use a button to handle authentication the first time.
function handleClientLoad() {
gapi.client.setApiKey(apiKey);
window.setTimeout(checkAuth,1);
}
function checkAuth() {
gapi.auth.authorize({client_id: clientId, scope: scopes, immediate: true}, handleAuthResult);
}
function handleAuthResult(authResult) {
var authorizeButton = document.getElementById('authorize-button');
if (authResult && !authResult.error) {
authorizeButton.style.visibility = 'hidden';
makeApiCall();
} else {
authorizeButton.style.visibility = '';
authorizeButton.onclick = handleAuthClick;
}
}
function handleAuthClick(event) {
gapi.auth.authorize({client_id: clientId, scope: scopes, immediate: false}, handleAuthResult);
return false;
}
// Load the API and make an API call. Display the results on the screen.
function makeApiCall() {
gapi.client.load('drive', 'v2', function() {
var request = gapi.client.drive.files.list ( {'maxResults': 5 } );
request.execute(function(resp) {
for (i=0; i<resp.items.length; i++) {
var titulo = resp.items[i].title;
var fechaUpd = resp.items[i].modifiedDate;
var userUpd = resp.items[i].lastModifyingUserName;
var fileInfo = document.createElement('li');
fileInfo.appendChild(document.createTextNode('TITLE: ' + titulo + ' - LAST MODIF: ' + fechaUpd + ' - BY: ' + userUpd ));
document.getElementById('content').appendChild(fileInfo);
}
});
});
}
</script>
<script src="https://apis.google.com/js/client.js?onload=handleClientLoad"></script>
<p><b>These are 5 files from your GDrive :)</b></p>
<div id="content"></div>
</body>
</html>
You only have to change:
你只需要改变:
- var clientId = '######';
- var apiKey = 'aaaaaaaaaaaaaaaaaaa';
- var clientId = '######';
- var apiKey = 'aaaaaaaaaaaaaaaaaa';
to your clientID and ApiKey from your Google API Console :)
从您的 Google API 控制台到您的 clientID 和 ApiKey :)
Of course you have to create your project on Google API Console, activate the Drive API and activate Google Accounts auth in OAuth 2.0 (really eeeeasy!)
当然,您必须在 Google API 控制台上创建您的项目,激活 Drive API 并激活 OAuth 2.0 中的 Google 帐户身份验证(真的很简单!)
PS: it wont work locally on your PC, it will work on some hosting, and yoy must provide the url from it on the project console :)
PS:它不能在您的 PC 本地运行,它可以在某些主机上运行,并且必须在项目控制台上提供它的 url :)