- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我编写了一个使用 Google Cloud Storage 保存图像文件的小型 Qt/С++ 应用程序。我在我的 Google API 控制台中创建了一个服务帐户客户端 ID,并尝试与 Google REST API 进行交互。但首先我需要获得 OAuth 授权 token 。
三天来我一直在尝试获取 token ,但每次我都遇到同样烦人的错误: { “错误”:“无效授权”
我尝试按照此处的建议调整时间:invalid_grant Returned using Service Account and Google Drive API .它没有帮助。
我按照本主题的建议在 Google API 控制台中创建了另一个客户端 ID:Invalid_grant in Google Analytics .没有结果。
这是我的小类(class)的代码,它请求 token 。请问有人能说我做错了什么吗?
#include "googlestorageuploader.h"
#include "openssl/evp.h"
#include "openssl/pem.h"
#include "openssl/bio.h"
#include "openssl/err.h"
#include "openssl/pkcs12.h"
#include <QFile>
#include <QDateTime>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QSslConfiguration>
#include <QDebug>
// Just a wrapper that takes OpenSsl function 'a' and calls it.
// If 'a' returns zero the wrapper throws a string containg description
// of error occured
#define OPENSSL_FUNCTION_CALL(a) \
if (!a) \
{ \
char buffer[120]; \
ERR_error_string(ERR_get_error(), buffer); \
char s[256]; \
sprintf(s, ""#a" function call failed.\n%s", buffer); \
throw s; \
} \
// String template for standard JWT Header
const QString kJwtHeader = "{\"alg\":\"RS256\",\"typ\":\"JWT\"}";
// String template for JWT claim set
// Contains two placeholders for "exp" and "iat" keys
const QString kJwtClaimSet = "{"
"\"iss\":\"XXXXXXXXXXXX-yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy@developer.gserviceaccount.com\","
"\"scope\":\"https://www.googleapis.com/auth/devstorage.readonly\","
"\"aud\":\"https://accounts.google.com/o/oauth2/token\","
"\"exp\":%1,"
"\"iat\":%2"
"}";
// This function computes JWT signature
// 'input' is an array of bytes passed as an input
// 'privateKey' is an array of bytes that contains a private key in PKCS12 format
// (as it is in the file received from 'Google APIs Console->API Access')
// Uses OpenSSL API to create a signature using SHA256withRSA
QByteArray signWithRsaSha256(const QByteArray &input, const QByteArray &privateKey)
{
EVP_PKEY *pkey = 0;
BIO *bp = 0;
EVP_MD_CTX *ctx = 0;
const EVP_MD *sha256Md = 0;
unsigned char sig[256];
unsigned int s(0);
QByteArray out;
PKCS12 *p12 = 0;
X509 *cert= 0;
OpenSSL_add_all_ciphers();
OpenSSL_add_all_digests();
ctx = EVP_MD_CTX_create();
EVP_MD_CTX_init(ctx);
sha256Md = EVP_sha256(); // TODO: need to free
bp = BIO_new_mem_buf((void*)privateKey.data(), privateKey.size());
try {
OPENSSL_FUNCTION_CALL(EVP_SignInit(ctx, sha256Md));
OPENSSL_FUNCTION_CALL(EVP_SignUpdate(ctx, input.constData(), input.size()));
OPENSSL_FUNCTION_CALL(d2i_PKCS12_bio(bp, &p12));
OPENSSL_FUNCTION_CALL(PKCS12_parse(p12, "notasecret", &pkey, &cert, NULL));
s = EVP_PKEY_size(pkey);
OPENSSL_FUNCTION_CALL(EVP_SignFinal(ctx, sig, &s, pkey));
out.setRawData((const char *)sig, s);
}
catch (const char *s)
{
qCritical() << s;
}
EVP_MD_CTX_destroy(ctx);
BIO_free(bp);
X509_free(cert);
EVP_cleanup();
return out;
}
CGoogleStorageUploader::CGoogleStorageUploader(QObject *parent) :
QObject(parent)
{
nam_ = new QNetworkAccessManager(this);
}
// Creates and sends HTTP POST request to get an authorization token
void CGoogleStorageUploader::requestToken()
{
QNetworkRequest req(QUrl("https://accounts.google.com/o/oauth2/token"));
req.setRawHeader("Host", "accounts.google.com");
req.setRawHeader("Content-Type", "application/x-www-form-urlencoded");
req.setSslConfiguration(QSslConfiguration::defaultConfiguration());
QByteArray assertion = formJWT();
QByteArray data;
data = "grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=" + assertion;
QNetworkReply *reply = nam_->post(req, data);
connect(reply, SIGNAL(finished()), SLOT(onNetworkReplyFinished()));
connect(reply, SIGNAL(sslErrors(QList<QSslError>)), SLOT(onNetworkReplySslErrors(QList<QSslError>)));
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(onNetworkReplyError(QNetworkReply::NetworkError)));
}
// Constructs JWT
QByteArray CGoogleStorageUploader::formJWT()
{
QDateTime now = QDateTime::currentDateTime();
QDateTime utcNow = now.toUTC();
quint32 secs = utcNow.toTime_t() - 300; // adjust to Google Server time
QString claimSet = kJwtClaimSet.arg(secs + 3600).arg(secs); // fill "exp" and "iat" fields
QByteArray signature, privateKey, jwt;
QFile file (":res/pk.p12"); // copy of file received from Google API Console
if (file.open(QFile::ReadOnly))
{
privateKey = file.readAll();
QByteArray encodedHeader = kJwtHeader.toUtf8().toBase64(); // serialize to UTF8 and Base64url safe encode (https://developers.google.com/accounts/docs/OAuth2ServiceAccount#formingclaimset)
QByteArray encodedClaimSet = claimSet.toUtf8().toBase64(); // serialize to UTF8 and Base64url safe encode (https://developers.google.com/accounts/docs/OAuth2ServiceAccount#formingclaimset)
// "Sign the UTF-8 representation of the input" (https://developers.google.com/accounts/docs/OAuth2ServiceAccount#computingsignature)
signature = signWithRsaSha256(QString(encodedHeader + "." + encodedClaimSet).toUtf8(), privateKey);
QByteArray encodedSignature = signature.toBase64();
jwt = encodedHeader + "." + encodedClaimSet + "." + encodedSignature;
}
file.close();
qDebug() << jwt;
return jwt;
}
void CGoogleStorageUploader::onNetworkReplyFinished()
{
QNetworkReply *r = static_cast<QNetworkReply*>(sender());
qDebug() << "finished: " << r->readAll();
}
void CGoogleStorageUploader::onNetworkReplySslErrors(const QList<QSslError> &errs)
{
QNetworkReply *r = static_cast<QNetworkReply*>(sender());
qDebug() << "ssl errors: " << r->readAll();
r->ignoreSslErrors(errs);
}
void CGoogleStorageUploader::onNetworkReplyError(QNetworkReply::NetworkError err)
{
qDebug() << "network error: " << err;
}
最佳答案
你不是必须先打电话才能获取验证码吗?获得代码后,您可以调用以获取 token ...
关于c++ - 使用 Google 云存储中的服务帐户获取 OAuth token 时出现“invalid_grant”错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15460520/
我正在开发一个应用程序,它使用 OAuth - 基于 token 的身份验证。 考虑到我们拥有访问和刷新 token ,这就是流程的样子。 Api call -> intercepter append
如何取消标记此代码的输出? 类(class)核心: def __init__(self, user_input): pos = pop(user_input) subject = ""
当我使用命令 kubectl 时与 --token标记并指定 token ,它仍然使用 kubeconfig 中的管理员凭据文件。 这是我做的: NAMESPACE="default" SERVICE
我正在制作 SPA,并决定使用 JWT 进行身份验证/授权,并且我已经阅读了一些关于 Tokens 与 Cookies 的博客。我了解 cookie 授权的工作原理,并了解基本 token 授权的工作
我正在尝试从应用服务获取 Google 的刷新 token ,但无法。 日志说 2016-11-04T00:04:25 PID[500] Verbose Received request: GET h
我正在开发一个项目,只是为了为 java 开发人员测试 eclipse IDE。我是java新手,所以我想知道为什么它不起作用,因为我已经知道该怎么做了。这是代码: public class ecli
我正在尝试使用 JwtSecurityTokenHandler 将 token 字符串转换为 jwt token 。但它出现错误说 IDX12709: CanReadToken() returned
我已阅读文档 Authentication (来自 Facebook 的官方)。我仍然不明白 Facebook 提供的这三种访问 token 之间的区别。网站上给出了一些例子,但我还是不太明白。 每个
我的部署服务器有时有这个问题,这让我抓狂,因为我无法在本地主机中重现,我已经尝试在我的 web.config 中添加机器 key ,但没有成功远。 它只发生在登录页面。 我的布局:
我已经设法获得了一个简单的示例代码,它可以创建一个不记名 token ,还可以通过阅读 stackoverflow 上的其他论坛来通过刷新 token 请求新的不记名 token 。 启动类是这样的
如果我有以前的刷新 token 和使用纯 php 的访问 token ,没有 Google Api 库,是否可以刷新 Google Api token ?我在数据库中存储了许多用户刷新和访问 toke
我通过 Java 应用程序使用 Google 电子表格时遇到了问题。我创建了应用程序,该应用程序运行了 1 年多,没有任何问题,我什至在 Create Spreadsheet using Google
当我有一个有效的刷新 token 时,我正在尝试使用 Keycloak admin REST API 重新创建访问 token 。 我已经通过调用 POST/auth/realms/{realm}/p
我正在尝试让第三方 Java 客户端与我编写的 WCF 服务进行通信。 收到消息时出现如下异常: Cannot find a token authenticator for the 'System.I
在尝试将数据插入到我的 SQl 数据库时,我收到以下错误 System.Data.SqlServerCe.SqlCeException: There was an error parsing the
使用数据库 session token 系统,我可以让用户使用用户名/密码登录,服务器可以生成 token (例如 uuid)并将其存储在数据库中并将该 token 返回给客户端。其上的每个请求都将包
我最近注册了 Microsoft Azure 并设置了认知服务帐户。使用 Text Translation API Documentation 中的说明我能够使用 interactive online
我使用 IAntiforgery API 创建了一个 ASP.Net Core 2 应用程序。 这提供了一种返回 cookie 的方法。 客户端获取该 cookie,并在后续 POST 请求中将该值放
我正在使用 spacy 来匹配某些文本(意大利语)中的特定表达式。我的文本可以多种形式出现,我正在尝试学习编写一般规则的最佳方式。我有如下 4 个案例,我想写一个适用于所有案例的通用模式。像这样的东西
我无法理解 oauth 2.0 token 的原则处理。 我的场景是,我有一个基于 web 的前端后端系统,带有 node.js 和 angular 2。用户应该能够在此站点上上传视频。然后创建一些额
我是一名优秀的程序员,十分优秀!