Qt OAuth2 浏览器支持

OAuth2 用户代理

OAuth2授权阶段 依赖于用户代理,用户代理通常是系统浏览器或嵌入式用户代理,如 Qt WebEngine.

选择系统浏览器还是嵌入式用户代理取决于多个因素。下面介绍几个主要考虑因素:

  • 系统浏览器可能已经有用户登录。因此,授权阶段的用户身份验证可能更简单,因为可以使用现有的登录名。而使用嵌入式用户代理时,用户通常需要重新登录。另一方面,在系统浏览器中留下登录会话并不总是可取的。系统浏览器还可能与其他方共享应用程序使用数据。
  • 系统浏览器通常为用户所熟悉,能为用户提供熟悉的登录体验。另一方面,虽然嵌入式用户代理可能不会提供熟悉的外观和感觉,但应用程序开发人员可以将登录交互作为应用程序窗口的一部分嵌入其中,而不是在单独的浏览器窗口中进行。此外,当不再需要时,应用程序开发人员可以自动关闭嵌入式用户代理。
  • 系统浏览器可为用户提供熟悉的安全视觉效果,如地址栏和证书验证。而这些在嵌入式用户代理上可能看不到。此外,系统浏览器可以更好地利用底层操作系统的安全功能。
  • 嵌入式用户代理有可能访问用户输入的所有安全凭证。
  • 并非所有平台都支持处理https 或自定义 uri-scheme 重定向 URL(参见QOAuthUriSchemeReplyHandler )。在这些平台上,可以使用嵌入式用户代理来绕过这一限制。
  • 将嵌入式用户代理作为应用程序的一部分通常是一个大型组件,会增加应用程序的存储空间。另一方面,所有用例可能都没有可用的系统浏览器,或者应用程序可能已经为其他目的使用了嵌入式用户代理。

考虑到这些因素,建议本地应用程序使用系统浏览器。但正如上述几点所暗示的,使用嵌入式用户代理可能仍有有效的用例。

使用系统浏览器

使用系统浏览器需要打开浏览器并导航到应用程序配置的授权 URL。典型用法如下:

connect(&m_oauth, &QAbstractOAuth::authorizeWithBrowser, this, &QDesktopServices::openUrl);

代码连接QAbstractOAuth::authorizeWithBrowser 信号和QDesktopServices::openUrl 插槽。这将打开系统浏览器,用户在其中执行必要的身份验证和授权。应用程序或 Qt 库对系统浏览器没有直接控制权,授权完成后,浏览器通常会保持打开状态。

有关系统浏览器的更多详情和支持的重定向 URL 方案,请参阅Qt OAuth2 概述QOAuthHttpServerReplyHandlerQOAuthUriSchemeReplyHandler

使用Qt WebEngine

Qt WebEngine提供了一个网络浏览器引擎,可将网络内容直接嵌入 Qt 应用程序。

除了核心控件功能外,它还为 QtWidgets 和 QtQuick 应用程序提供了易于使用的视图。这些视图可用作 OAuth2 授权中的用户代理。 Qt WebEngineQtWidget 是一个大型的多功能模块,本文档的重点是将其与 OAuth2 授权结合使用。

有许多方法可以将 Qt XMLWebEngine 作为应用程序的一部分嵌入。从实用的角度来看,主要的考虑因素如下:

  • QtQuick 与 QtWidgets 应用程序。这将影响如何设置与QtNetworkAuth 类的必要集成。
  • 重定向 URI 方案。这将影响使用哪些QtNetworkAuth 回复处理程序类,以及如何使用(请参阅Qt OAuth2 概述)。

QtQuick 和 QtWidgets 应用程序

QtWebEngine 可与 QtQuick 和 QtWidgets 应用程序一起用于 OAuth2 授权。主要区别在于如何设置几个必要的启用程序。

下面展示了一个简化的QWebEngineView (QtWidget) 设置。为简洁起见 Qt WebEngine为简洁起见,省略了错误处理和任何可能的配置。

假定使用以下部件:

QWebEngineView *webView = nullptr;
QMainWindow mainWindow;

我们使用QWebEngineView 来执行授权,而不是打开系统浏览器:

connect(&m_oauth, &QAbstractOAuth::authorizeWithBrowser, this, [this](const QUrl &url) {
    mainWindow.show();
    webView->load(url);
    webView->show();
});

授权完成后,我们关闭视图:

connect(&m_oauth, &QAbstractOAuth::granted, this, [this]() {
    // Here we use QNetworkRequestFactory to store the access token
    m_api.setBearerToken(m_oauth.token().toLatin1());
    m_handler->close();
    webView->close();
});

对于 QtQuick 应用程序,流程原则上是相同的,但我们使用WebEngineView QML 元素来代替QWebEngineView widget:

WebEngineView {
    id: authorizationWebView
    anchors.fill: parent
    visible: false
}

这个简化示例从 C++ 类中公开了所需的 API。

class HttpExample : public QObject
{
    Q_OBJECT
#ifdef QT_QML_LIB
    QML_NAMED_ELEMENT(OAuth2)
#endif
public:
    Q_INVOKABLE void authorize();

signals:
    void authorizationCompleted(bool success);
    void authorizeWithBrowser(const QUrl &url);

然后在 QML 端调用WebEngineView 来处理授权:

onAuthorizeWithBrowser:
    (url) => {
        console.log("Starting authorization with WebView")
        authorizationWebView.url = url
        authorizationWebView.visible = true
    }
onAuthorizationCompleted:
    (success) => {
        console.log("Authorized: " + success);
        authorizationWebView.visible = false
    }

重定向 URI 方案

重定向 URI 方案(httphttpscustom-uri 方案)的选择会影响如何使用 Qt WebEngine.

http 回环重定向 URI

http 回环重定向 URI 和QOAuthHttpServerReplyHandler 的处理方法与系统浏览器类似。Qt XMLWebEngine 会将授权重定向到回复处理程序的 localhost 服务器,与系统浏览器类似。

自定义方案 URI

对于自定义方案 URI(如com.example.myqtapp:/redirect )和QOAuthUriSchemeReplyHandler ,处理流程也与系统浏览器类似。

主要区别在于,应用程序不需要像iOS/macOS 上的通用链接Android 上的应用链接那样进行配置,如QOAuthUriSchemeReplyHandler 文档所述。

m_handler.setRedirectUrl(QUrl{"com.example.myqtapp://oauth2redirect"_L1});
m_oauth.setReplyHandler(&m_handler);

connect(&m_oauth, &QAbstractOAuth::authorizeWithBrowser, this, [this](const QUrl &url) {
    mainWindow.show();
    webView->load(url);
    webView->show();
});
connect(&m_oauth, &QAbstractOAuth::granted, this, [this]() {
    // Here we use QNetworkRequestFactory to store the access token
    m_api.setBearerToken(m_oauth.token().toLatin1());
    m_handler.close();
    webView->close();
});

技术上的工作原理是 Qt WebEngine调用QDesktopServices::openUrl() 来处理未处理的 URI-schemes,其对应的QOAuthUriSchemeReplyHandler 会监听。

https URI

https URI 和QOAuthUriSchemeReplyHandler 的逻辑略有不同。与自定义方案 URI类似,应用程序无需配置,但我们需要在授权阶段结束时向网络引擎提供重定向。

connect(webView, &QWebEngineView::urlChanged, this, [this](const QUrl &url){
    m_handler.handleAuthorizationRedirect(url);
});

之所以需要这样做,是因为 Qt WebEngine来看,重定向 URL 是一个有效的https URL,默认情况下会尝试导航到它。

为防止此类导航尝试和意外的授权代码暴露(考虑到重定向 URL 域不在您的控制范围内),应使用更复杂的过滤方法。此外,强烈建议使用QOAuth2AuthorizationCodeFlow::PkceMethod ,因为它可以减轻授权代码劫持的影响。

例如

connect(webView->page(), &QWebEnginePage::navigationRequested,
        this, [this](QWebEngineNavigationRequest &request) {
    if (request.navigationType() == QWebEngineNavigationRequest::RedirectNavigation
        && m_handler.handleAuthorizationRedirect(request.url())) {
        request.reject();
        webView->close();
    } else {
        request.accept();
    }
});

© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.