Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/164.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ ';无效的授权';在Google云存储中使用服务帐户获取OAuth令牌时出错_C++_Qt_Openssl_Google Oauth - Fatal编程技术网

C++ ';无效的授权';在Google云存储中使用服务帐户获取OAuth令牌时出错

C++ ';无效的授权';在Google云存储中使用服务帐户获取OAuth令牌时出错,c++,qt,openssl,google-oauth,C++,Qt,Openssl,Google Oauth,我已经编写了一个小的Qt/С++应用程序,它使用谷歌云存储来保存图像文件。我在GoogleAPI控制台中创建了一个服务帐户客户端ID,并尝试与GoogleRESTAPI交互。但首先我需要获得OAuth授权令牌 我三天来一直在尝试获取代币,但每次都会遇到相同的恼人错误: { “错误”:“无效的授权” } 我试图按照此处的建议调整时间:。这没用 我在Google API控制台中创建了另一个客户端ID,正如本主题所示:。没有结果 这是我的一个请求令牌的小类的代码。谁能说说我做错了什么 #include

我已经编写了一个小的Qt/С++应用程序,它使用谷歌云存储来保存图像文件。我在GoogleAPI控制台中创建了一个服务帐户客户端ID,并尝试与GoogleRESTAPI交互。但首先我需要获得OAuth授权令牌

我三天来一直在尝试获取代币,但每次都会遇到相同的恼人错误: { “错误”:“无效的授权” }

我试图按照此处的建议调整时间:。这没用

我在Google API控制台中创建了另一个客户端ID,正如本主题所示:。没有结果

这是我的一个请求令牌的小类的代码。谁能说说我做错了什么

#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;
}
#包括“googlestorageuploader.h”
#包括“openssl/evp.h”
#包括“openssl/pem.h”
#包括“openssl/bio.h”
#包括“openssl/err.h”
#包括“openssl/pkcs12.h”
#包括
#包括
#包括
#包括
#包括
#包括
//只是一个接受OpenSsl函数“a”并调用它的包装器。
//如果“a”返回零,包装器将抛出一个包含描述的字符串
//发生了一系列错误
#定义OPENSSL_函数_调用(a)\
如果(!a)\
{ \
字符缓冲区[120]\
ERR_error_字符串(ERR_get_error(),buffer)\
chars[256]\
sprintf(s,“#a”函数调用失败。\n%s”,缓冲区)\
掷骰子\
} \
//标准JWT头的字符串模板
常量QString kJwtHeader=“{\'alg\':\'RS256\',\'typ\':\'JWT\'”;
//JWT索赔集的字符串模板
//包含“exp”和“iat”键的两个占位符
常量QString kJwtClaimSet=“{”
“\”iss\:\”XXXXXXXXXX-yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy@developer.gserviceaccount.com\","
“\”范围\“:\”https://www.googleapis.com/auth/devstorage.readonly\","
“\”澳元\“:\”https://accounts.google.com/o/oauth2/token\","
“\“exp\”:%1,”
“\“iat\”:%2”
"}";
//此函数用于计算JWT签名
//“input”是作为输入传递的字节数组
//“privateKey”是包含PKCS12格式私钥的字节数组
//(正如从“谷歌API控制台->API访问”接收的文件中所示)
//使用OpenSSL API使用SHA256withRSA创建签名
QByteArray标志带RSASA256(常量QByteArray和输入、常量QByteArray和私钥)
{
EVP_PKEY*PKEY=0;
BIO*bp=0;
EVP_MD_CTX*CTX=0;
const EVP_MD*sha256Md=0;
无符号字符sig[256];
无符号整数s(0);
QByteArray out;
PKCS12*p12=0;
X509*证书=0;
OpenSSL_添加所有密码();
OpenSSL_添加_所有_摘要();
ctx=EVP_MD_ctx_create();
执行副总裁MD CTX init(CTX);
sha256Md=EVP_sha256();//TODO:需要释放
bp=BIO_new_mem_buf((void*)privateKey.data(),privateKey.size());
试一试{
OPENSSL函数调用(EVP符号(ctx,sha256Md));
OPENSSL_函数_调用(EVP_SignUpdate(ctx,input.constData(),input.size());
OPENSSL_函数_调用(d2i_PKCS12_bio(bp和p12));
OPENSSL_函数_调用(PKCS12_解析(p12,“notasecret”,&pkey,&cert,NULL));
s=EVP_PKEY_尺寸(PKEY);
OPENSSL_函数_调用(EVP_SignFinal(ctx,sig,&s,pkey));
out.setRawData((const char*)sig,s);
}
捕获(常量字符*s)
{
qCritical()post(请求,数据);
连接(应答,信号(finished()),插槽(onNetworkReplyFinished());
连接(应答、信号(sslErrors(QList))、插槽(onNetworkReplySslErrors(QList));
连接(应答,信号(错误(QNetworkReply::NetworkError)),插槽(onNetworkReplyError(QNetworkReply::NetworkError));
}
//构造JWT
QByteArray CGoogleStorageUploader::formJWT()
{
QDateTime now=QDateTime::currentDateTime();
QDateTime utcNow=now.toUTC();
quint32 secs=utcNow.toTime\u t()-300;//调整到Google服务器时间
QString claimSet=kJwtClaimSet.arg(secs+3600).arg(secs);//填充“exp”和“iat”字段
QByteArray签名,私钥,jwt;
QFile文件(“:res/pk.p12”);//从Google API控制台接收的文件副本
if(file.open(QFile::ReadOnly))
{
privateKey=file.readAll();
QByteArray encodedHeader=kJwtHeader.toUtf8().toBase64();//序列化为UTF8和Base64url安全编码(https://developers.google.com/accounts/docs/OAuth2ServiceAccount#formingclaimset)
QByteArray encodedClaimSet=claimSet.toUtf8().toBase64();//序列化为UTF8和Base64url安全编码(https://developers.google.com/accounts/docs/OAuth2ServiceAccount#formingclaimset)
//“对输入的UTF-8表示形式进行签名”(https://developers.google.com/accounts/docs/OAuth2ServiceAccount#computingsignature)
signature=SignWithRSASA256(QString(encodedHeader+““+encodedClaimSet).toUtf8(),privateKey);
QByteArray encodedSignature=signature.toBase64();
jwt=encodedHeader+“+”encodedClaimSet+“+”encodedSignature;
}
file.close();

qDebug()你不需要先打个电话才能得到代码吗?
获得代码后,您可以拨打电话获取令牌…

对不起,通过拨打电话,我必须首先获取什么代码?我正在使用服务帐户获取OAuth访问令牌,如这里所述