如何使用QOAuth2AuthorizationCodeFlow和QOAuthHttpServerReplyHandler设置redirect_uri

时间:2017-03-04 11:03:47

标签: c++ qt oauth-2.0

对于使用QT的networkauth和新的QOAuth2AuthorizationCodeFlow对象的OAuth 2.0,如何设置redirect_uri?我的代码如下。它会导致发送以下身份验证URL:

QOAuth2AuthorizationCodeFlow :: buildAuthenticateUrl:https://accounts.google.com/o/oauth2/auth?client_id=123-abc.apps.googleusercontent.com&redirect_uri=http://localhost:65535/cb&response_type=code&scope=email&state=iEIYn5sN

将redirect_uri设置为" http://localhost",会导致谷歌出现错误400 redirect_uri_mismatch,显然需要提供实际的重定向主机名。

GoogleGateway::GoogleGateway() {

auto google = new QOAuth2AuthorizationCodeFlow;
google->setScope("email");

this->connect(google, &QOAuth2AuthorizationCodeFlow::authorizeWithBrowser, &QDesktopServices::openUrl);

QString val;
QFile file;
file.setFileName("/home/me/client_secret.json");
file.open(QIODevice::ReadOnly | QIODevice::Text);
val = file.readAll();
file.close();

QJsonDocument document = QJsonDocument::fromJson(val.toUtf8());
QJsonObject object = document.object();
const auto settingsObject = object["web"].toObject();
const QUrl authUri(settingsObject["auth_uri"].toString());
const auto clientId = settingsObject["client_id"].toString();
const QUrl tokenUri(settingsObject["token_uri"].toString());
const auto clientSecret(settingsObject["client_secret"].toString());
const auto redirectUris = settingsObject["redirect_uris"].toArray();
const QUrl redirectUri(redirectUris[0].toString());
const auto port = static_cast<quint16>(redirectUri.port());

google->setAuthorizationUrl(authUri);
google->setClientIdentifier(clientId);
google->setAccessTokenUrl(tokenUri);
google->setClientIdentifierSharedKey(clientSecret);

auto replyHandler = new QOAuthHttpServerReplyHandler(port, this);
google->setReplyHandler(replyHandler);

google->grant();
}

要设置redirect_uri,我已尝试更换:

auto replyHandler = new QOAuthHttpServerReplyHandler(port, this);

QHostAddress hostaddress = QHostAddress(quint32(1233...));
auto replyHandler = new QOAuthHttpServerReplyHandler(hostaddress, port, this);

结果没有变化。

还试过插入:

replyHandler->setProperty("redirect_uri", "http://abc.xyz.com:65535/cb");

也没有改变结果。

在Qt / 5.8 / Src / qtnetworkauth / src / oauth / qoauthhttpserverreplyhandler.cpp中,我们看到回调地址看起来很可疑硬编码:

QString QOAuthHttpServerReplyHandler::callback() const
{
    Q_D(const QOAuthHttpServerReplyHandler);

    Q_ASSERT(d->httpServer.isListening());
    const QUrl url(QString::fromLatin1("http://localhost:%1/cb").arg(d->httpServer.serverPort()));
    return url.toString(QUrl::EncodeDelimiters);
}

这个callback()依次用于Qt / 5.8 / Src / qtnetworkauth / src / oauth / qoauth2authorizationcodeflow.cpp来设置redirectUri值:

QUrl QOAuth2AuthorizationCodeFlow::buildAuthenticateUrl(const QVariantMap &parameters)
{
    Q_D(QOAuth2AuthorizationCodeFlow);
    using Key = QAbstractOAuth2Private::OAuth2KeyString;

    if (d->state.isEmpty())
        setState(QAbstractOAuth2Private::generateRandomState());
    Q_ASSERT(!d->state.isEmpty());
    const QString state = d->state;

    QVariantMap p(parameters);
    QUrl url(d->authorizationUrl);
    p.insert(Key::responseType, responseType());
    p.insert(Key::clientIdentifier, d->clientCredentials.first);
    p.insert(Key::redirectUri, callback());
    p.insert(Key::scope, d->scope);
    p.insert(Key::state, state);
    if (d->modifyParametersFunction)
        d->modifyParametersFunction(Stage::RequestingAuthorization, &p);
    url.setQuery(d->createQuery(p));
    connect(d->replyHandler.data(), &QAbstractOAuthReplyHandler::callbackReceived, this,
            &QOAuth2AuthorizationCodeFlow::authorizationCallbackReceived, Qt::UniqueConnection);
    setStatus(QAbstractOAuth::Status::NotAuthenticated);
    qDebug("QOAuth2AuthorizationCodeFlow::buildAuthenticateUrl: %s", qPrintable(url.toString()));
    return url;
}

这是一个错误吗?

3 个答案:

答案 0 :(得分:1)

我刚刚通过继承MyOAuthHttpServerReplyHandler并覆盖callback()的定义来解决这个问题,以返回我想要的URI。

答案 1 :(得分:0)

我使用的是Qt 5.15,redirect_uri可以更改为QAbstractOAuth::modifyParametersFunction

m_google = new QOAuth2AuthorizationCodeFlow(m_manager,this);
// set other parameters...
m_google->setModifyParametersFunction(buildModifyParametersFunction());

// return ModifyParametersFunction()
QAbstractOAuth::ModifyParametersFunction GoogleOAuth2Wrapper::buildModifyParametersFunction()
{
    const QUrl clientIdentifier = m_google->clientIdentifier();
    const QUrl clientIdentifierSharedKey = m_google->clientIdentifierSharedKey();
    return [clientIdentifier,clientIdentifierSharedKey]
            (QAbstractOAuth::Stage stage, QVariantMap *parameters){
        if(stage == QAbstractOAuth::Stage::RequestingAuthorization){
            parameters->insert("redirect_uri","https://127.0.0.1:8080/cb"); /*change redirect uri*/
        }
    };
}

QOAuth2AuthorizationCodeFlow类使用QUrl buildAuthenticateUrl(const QVariantMap &parameters)方法向浏览器发送访问令牌,这是源代码:

QUrl QOAuth2AuthorizationCodeFlow::buildAuthenticateUrl(const QVariantMap &parameters)
{
    Q_D(QOAuth2AuthorizationCodeFlow);
    using Key = QAbstractOAuth2Private::OAuth2KeyString;
    if (d->state.isEmpty())
        setState(QAbstractOAuth2Private::generateRandomState());
    Q_ASSERT(!d->state.isEmpty());
    const QString state = d->state;
    QVariantMap p(parameters);
    QUrl url(d->authorizationUrl);
    p.insert(Key::responseType, responseType());
    p.insert(Key::clientIdentifier, d->clientIdentifier);
    p.insert(Key::redirectUri, callback());
    p.insert(Key::scope, d->scope);
    p.insert(Key::state, state);
    if (d->modifyParametersFunction) /** Here's what we take part **/
        d->modifyParametersFunction(Stage::RequestingAuthorization, &p);
    url.setQuery(d->createQuery(p));
    connect(d->replyHandler.data(), &QAbstractOAuthReplyHandler::callbackReceived, this,
            &QOAuth2AuthorizationCodeFlow::authorizationCallbackReceived, Qt::UniqueConnection);
    setStatus(QAbstractOAuth::Status::NotAuthenticated);
    qCDebug(d->loggingCategory, "Generated URL: %s", qPrintable(url.toString()));
    return url;
}

我希望这会有所帮助。

参考

QAbstractOAuth::modifyParametersFunction

QOAuth2AuthorizationCodeFlow::buildAuthenticateUrl source

答案 2 :(得分:0)

使用 Qt 5.15,覆盖重定向 URI 不再是问题,但您可能会遇到另外两个问题:

  • 如果您使用 Google 凭据 JSON 中提供的第一个网址,您的应用可能在授权流程结束时收不到用户浏览器的回复。相反,只需使用可靠的用户机器 http://127.0.0.1:1234/
  • 取决于您的运气,Google 返回的登录代码是经过 URL 编码的,其中可能包含在向 Google 本身请求登录令牌之前需要进行 URL 解码的字符。这是我希望 Qt 为您处理的事情,但您必须注入参数修饰符。

这是关键块,摘自我们在 authenticating a Qt app with Google SSO 上的帖子:

this->google->setModifyParametersFunction([](QAbstractOAuth::Stage stage, QVariantMap* parameters) {
   // Percent-decode the "code" parameter so Google can match it
   if (stage == QAbstractOAuth::Stage::RequestingAccessToken) {
      QByteArray code = parameters->value("code").toByteArray();
      (*parameters)["code"] = QUrl::fromPercentEncoding(code);
   }
});