diff options
author | Anu Aliyas <anu.aliyas@qt.io> | 2023-05-12 13:32:12 +0200 |
---|---|---|
committer | Anu Aliyas <anu.aliyas@qt.io> | 2023-07-12 17:20:57 +0200 |
commit | 605b0b3dcce24ff82c1e7a1ab3db7dace9668b81 (patch) | |
tree | e688549a6ef361f243ec82a406abb875ae0ee371 /examples/webenginewidgets/simplebrowser | |
parent | a3452104907874f4a3ffee83ec99c639004405e6 (diff) |
Support FIDO2 user verification
- Implemented AuthenticatorRequestClientDelegateQt support to handle authenticator requests.
- Added FIDO user verification and resident credential support
Fixes: QTBUG-90938
Fixes: QTBUG-90941
Change-Id: I6367791e1e9e8aaac27c376408377f838832f426
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'examples/webenginewidgets/simplebrowser')
8 files changed, 552 insertions, 3 deletions
diff --git a/examples/webenginewidgets/simplebrowser/CMakeLists.txt b/examples/webenginewidgets/simplebrowser/CMakeLists.txt index cb0769e77..a572e53f5 100644 --- a/examples/webenginewidgets/simplebrowser/CMakeLists.txt +++ b/examples/webenginewidgets/simplebrowser/CMakeLists.txt @@ -27,6 +27,7 @@ qt_add_executable(simplebrowser webpage.cpp webpage.h webpopupwindow.cpp webpopupwindow.h webview.cpp webview.h + webauthdialog.cpp webauthdialog.h webauthdialog.ui ) if(WIN32) diff --git a/examples/webenginewidgets/simplebrowser/doc/src/simplebrowser.qdoc b/examples/webenginewidgets/simplebrowser/doc/src/simplebrowser.qdoc index f45b362df..afec5e7e0 100644 --- a/examples/webenginewidgets/simplebrowser/doc/src/simplebrowser.qdoc +++ b/examples/webenginewidgets/simplebrowser/doc/src/simplebrowser.qdoc @@ -321,6 +321,30 @@ finished or when an error occurs. See \c downloadmanagerwidget.cpp for an example of how these signals can be handled. + \section1 Managing WebAuth/FIDO UX Requests + + WebAuth UX requests are associated with \l QWebEnginePage. Whenever an authenticator + requires user interaction, a UX request is triggered on the QWebEnginePage and + the \l QWebEnginePage::webAuthUXRequested signal is emitted with + \l QWebEngineWebAuthUXRequest, which in this example is forwarded + to \c WebView::handleAuthenticatorRequired: + + \quotefromfile webenginewidgets/simplebrowser/webview.cpp + \skipto connect(page, &QWebEnginePage::webAuthUXRequested + \printline connect(page, &QWebEnginePage::webAuthUXRequested + + This method creates a WebAuth UX dialog and initiates the UX request flow. + + \quotefromfile webenginewidgets/simplebrowser/webview.cpp + \skipto void WebView::handleWebAuthUXRequested(QWebEngineWebAuthUXRequest *request) + \printuntil /^\}/ + + The \l QWebEngineWebAuthUXRequest object periodically emits the \l + {QWebEngineWebAuthUXRequest::}{stateChanged} signal to notify potential + observers of the current WebAuth UX states. The observers update the WebAuth + dialog accordingly. See \c webview.cpp and \c webauthdialog.cpp for an example + of how these signals can be handled. + \section1 Files and Attributions The example uses icons from the Tango Icon Library: diff --git a/examples/webenginewidgets/simplebrowser/simplebrowser.pro b/examples/webenginewidgets/simplebrowser/simplebrowser.pro index d4cce7738..8598d237a 100644 --- a/examples/webenginewidgets/simplebrowser/simplebrowser.pro +++ b/examples/webenginewidgets/simplebrowser/simplebrowser.pro @@ -10,7 +10,8 @@ HEADERS += \ tabwidget.h \ webpage.h \ webpopupwindow.h \ - webview.h + webview.h \ + webauthdialog.h SOURCES += \ browser.cpp \ @@ -21,7 +22,8 @@ SOURCES += \ tabwidget.cpp \ webpage.cpp \ webpopupwindow.cpp \ - webview.cpp + webview.cpp \ + webauthdialog.cpp win32 { CONFIG -= embed_manifest_exe @@ -32,7 +34,8 @@ FORMS += \ certificateerrordialog.ui \ passworddialog.ui \ downloadmanagerwidget.ui \ - downloadwidget.ui + downloadwidget.ui \ + webauthdialog.ui RESOURCES += data/simplebrowser.qrc diff --git a/examples/webenginewidgets/simplebrowser/webauthdialog.cpp b/examples/webenginewidgets/simplebrowser/webauthdialog.cpp new file mode 100644 index 000000000..f153667fe --- /dev/null +++ b/examples/webenginewidgets/simplebrowser/webauthdialog.cpp @@ -0,0 +1,294 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "webauthdialog.h" + +#include <QVBoxLayout> +#include <QRadioButton> +#include <QLineEdit> +#include <QTextEdit> +#include <QPushButton> +#include <QWebEngineView> + +WebAuthDialog::WebAuthDialog(QWebEngineWebAuthUXRequest *request, QWidget *parent) + : QDialog(parent), uxRequest(request), uiWebAuthDialog(new Ui::WebAuthDialog) +{ + uiWebAuthDialog->setupUi(this); + + buttonGroup = new QButtonGroup(this); + buttonGroup->setExclusive(true); + + scrollArea = new QScrollArea(this); + selectAccountWidget = new QWidget(this); + scrollArea->setWidget(selectAccountWidget); + scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + selectAccountWidget->resize(400, 150); + selectAccountLayout = new QVBoxLayout(selectAccountWidget); + uiWebAuthDialog->m_mainVerticalLayout->addWidget(scrollArea); + selectAccountLayout->setAlignment(Qt::AlignTop); + + updateDisplay(); + + connect(uiWebAuthDialog->buttonBox, &QDialogButtonBox::rejected, this, + qOverload<>(&WebAuthDialog::onCancelRequest)); + + connect(uiWebAuthDialog->buttonBox, &QDialogButtonBox::accepted, this, + qOverload<>(&WebAuthDialog::onAcceptRequest)); + QAbstractButton *button = uiWebAuthDialog->buttonBox->button(QDialogButtonBox::Retry); + connect(button, &QAbstractButton::clicked, this, qOverload<>(&WebAuthDialog::onRetry)); + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding); +} + +WebAuthDialog::~WebAuthDialog() +{ + QList<QAbstractButton *> buttons = buttonGroup->buttons(); + auto itr = buttons.begin(); + while (itr != buttons.end()) { + QAbstractButton *radioButton = *itr; + delete radioButton; + itr++; + } + + if (buttonGroup) { + delete buttonGroup; + buttonGroup = nullptr; + } + + if (uiWebAuthDialog) { + delete uiWebAuthDialog; + uiWebAuthDialog = nullptr; + } + + // selectAccountWidget and it's children will get deleted when scroll area is destroyed + if (scrollArea) { + delete scrollArea; + scrollArea = nullptr; + } +} + +void WebAuthDialog::updateDisplay() +{ + switch (uxRequest->state()) { + case QWebEngineWebAuthUXRequest::SelectAccount: + setupSelectAccountUI(); + break; + case QWebEngineWebAuthUXRequest::CollectPIN: + setupCollectPINUI(); + break; + case QWebEngineWebAuthUXRequest::FinishTokenCollection: + setupFinishCollectTokenUI(); + break; + case QWebEngineWebAuthUXRequest::RequestFailed: + setupErrorUI(); + break; + default: + break; + } + adjustSize(); +} + +void WebAuthDialog::setupSelectAccountUI() +{ + uiWebAuthDialog->m_headingLabel->setText(tr("Choose a Passkey")); + uiWebAuthDialog->m_description->setText(tr("Which passkey do you want to use for ") + + uxRequest->relyingPartyId() + tr("? ")); + uiWebAuthDialog->m_pinGroupBox->setVisible(false); + uiWebAuthDialog->m_mainVerticalLayout->removeWidget(uiWebAuthDialog->m_pinGroupBox); + uiWebAuthDialog->buttonBox->button(QDialogButtonBox::Retry)->setVisible(false); + + clearSelectAccountButtons(); + scrollArea->setVisible(true); + selectAccountWidget->resize(this->width(), this->height()); + QStringList userNames = uxRequest->userNames(); + // Create radio buttons for each name + for (const QString &name : userNames) { + QRadioButton *radioButton = new QRadioButton(name); + selectAccountLayout->addWidget(radioButton); + buttonGroup->addButton(radioButton); + } + + uiWebAuthDialog->buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Ok")); + uiWebAuthDialog->buttonBox->button(QDialogButtonBox::Ok)->setVisible(true); + uiWebAuthDialog->buttonBox->button(QDialogButtonBox::Cancel)->setVisible(true); + uiWebAuthDialog->buttonBox->button(QDialogButtonBox::Retry)->setVisible(false); +} + +void WebAuthDialog::setupFinishCollectTokenUI() +{ + clearSelectAccountButtons(); + uiWebAuthDialog->m_headingLabel->setText(tr("Use your security key with") + + uxRequest->relyingPartyId()); + uiWebAuthDialog->m_description->setText( + tr("Touch your security key again to complete the request.")); + uiWebAuthDialog->m_pinGroupBox->setVisible(false); + uiWebAuthDialog->buttonBox->button(QDialogButtonBox::Ok)->setVisible(false); + uiWebAuthDialog->buttonBox->button(QDialogButtonBox::Retry)->setVisible(false); + scrollArea->setVisible(false); +} +void WebAuthDialog::setupCollectPINUI() +{ + clearSelectAccountButtons(); + uiWebAuthDialog->m_mainVerticalLayout->addWidget(uiWebAuthDialog->m_pinGroupBox); + uiWebAuthDialog->m_pinGroupBox->setVisible(true); + uiWebAuthDialog->m_confirmPinLabel->setVisible(false); + uiWebAuthDialog->m_confirmPinLineEdit->setVisible(false); + uiWebAuthDialog->buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Next")); + uiWebAuthDialog->buttonBox->button(QDialogButtonBox::Ok)->setVisible(true); + uiWebAuthDialog->buttonBox->button(QDialogButtonBox::Cancel)->setVisible(true); + uiWebAuthDialog->buttonBox->button(QDialogButtonBox::Retry)->setVisible(false); + scrollArea->setVisible(false); + + QWebEngineWebAuthPINRequest pinRequestInfo = uxRequest->pinRequest(); + + if (pinRequestInfo.reason == QWebEngineWebAuthUXRequest::PINEntryReason::Challenge) { + uiWebAuthDialog->m_headingLabel->setText(tr("PIN Required")); + uiWebAuthDialog->m_description->setText(tr("Enter the PIN for your security key")); + uiWebAuthDialog->m_confirmPinLabel->setVisible(false); + uiWebAuthDialog->m_confirmPinLineEdit->setVisible(false); + } else { + if (pinRequestInfo.reason == QWebEngineWebAuthUXRequest::PINEntryReason::Set) { + uiWebAuthDialog->m_headingLabel->setText(tr("New PIN Required")); + uiWebAuthDialog->m_description->setText(tr("Set new PIN for your security key")); + } else { + uiWebAuthDialog->m_headingLabel->setText(tr("Change PIN Required")); + uiWebAuthDialog->m_description->setText(tr("Change PIN for your security key")); + } + uiWebAuthDialog->m_confirmPinLabel->setVisible(true); + uiWebAuthDialog->m_confirmPinLineEdit->setVisible(true); + } + + QString errorDetails; + switch (pinRequestInfo.error) { + case QWebEngineWebAuthUXRequest::PINEntryError::NoError: + break; + case QWebEngineWebAuthUXRequest::PINEntryError::InternalUvLocked: + errorDetails = tr("Internal User Verification Locked "); + break; + case QWebEngineWebAuthUXRequest::PINEntryError::WrongPIN: + errorDetails = tr("Wrong Pin"); + break; + case QWebEngineWebAuthUXRequest::PINEntryError::TooShort: + errorDetails = tr("Too Short"); + break; + case QWebEngineWebAuthUXRequest::PINEntryError::InvalidCharacters: + errorDetails = tr("Invalid Characters"); + break; + case QWebEngineWebAuthUXRequest::PINEntryError::SameAsCurrentPIN: + errorDetails = tr("Same as current PIN"); + break; + } + if (!errorDetails.isEmpty()) { + errorDetails += tr(" ") + QString::number(pinRequestInfo.remainingAttempts) + + tr(" attempts remaining"); + } + uiWebAuthDialog->m_pinEntryErrorLabel->setText(errorDetails); +} + +void WebAuthDialog::onCancelRequest() +{ + uxRequest->cancel(); +} + +void WebAuthDialog::onAcceptRequest() +{ + switch (uxRequest->state()) { + case QWebEngineWebAuthUXRequest::SelectAccount: + if (buttonGroup->checkedButton()) { + uxRequest->setSelectedAccount(buttonGroup->checkedButton()->text()); + } + break; + case QWebEngineWebAuthUXRequest::CollectPIN: + uxRequest->setPin(uiWebAuthDialog->m_pinLineEdit->text()); + break; + default: + break; + } +} + +void WebAuthDialog::setupErrorUI() +{ + clearSelectAccountButtons(); + QString errorDescription; + QString errorHeading = tr("Something went wrong"); + bool isVisibleRetry = false; + switch (uxRequest->requestFailureReason()) { + case QWebEngineWebAuthUXRequest::RequestFailureReason::Timeout: + errorDescription = tr("Request Timeout"); + break; + case QWebEngineWebAuthUXRequest::RequestFailureReason::KeyNotRegistered: + errorDescription = tr("Key not registered"); + break; + case QWebEngineWebAuthUXRequest::RequestFailureReason::KeyAlreadyRegistered: + errorDescription = tr("You already registered this device." + "Try again with device"); + isVisibleRetry = true; + break; + case QWebEngineWebAuthUXRequest::RequestFailureReason::SoftPINBlock: + errorDescription = + tr("The security key is locked because the wrong PIN was entered too many times." + "To unlock it, remove and reinsert it."); + isVisibleRetry = true; + break; + case QWebEngineWebAuthUXRequest::RequestFailureReason::HardPINBlock: + errorDescription = + tr("The security key is locked because the wrong PIN was entered too many times." + " You'll need to reset the security key."); + break; + case QWebEngineWebAuthUXRequest::RequestFailureReason::AuthenticatorRemovedDuringPINEntry: + errorDescription = + tr("Authenticator removed during verification. Please reinsert and try again"); + break; + case QWebEngineWebAuthUXRequest::RequestFailureReason::AuthenticatorMissingResidentKeys: + errorDescription = tr("Authenticator doesn't have resident key support"); + break; + case QWebEngineWebAuthUXRequest::RequestFailureReason::AuthenticatorMissingUserVerification: + errorDescription = tr("Authenticator missing user verification"); + break; + case QWebEngineWebAuthUXRequest::RequestFailureReason::AuthenticatorMissingLargeBlob: + errorDescription = tr("Authenticator missing Large Blob support"); + break; + case QWebEngineWebAuthUXRequest::RequestFailureReason::NoCommonAlgorithms: + errorDescription = tr("Authenticator missing Large Blob support"); + break; + case QWebEngineWebAuthUXRequest::RequestFailureReason::StorageFull: + errorDescription = tr("Storage Full"); + break; + case QWebEngineWebAuthUXRequest::RequestFailureReason::UserConsentDenied: + errorDescription = tr("User consent denied"); + break; + case QWebEngineWebAuthUXRequest::RequestFailureReason::WinUserCancelled: + errorDescription = tr("User Cancelled Request"); + break; + } + + uiWebAuthDialog->m_headingLabel->setText(errorHeading); + uiWebAuthDialog->m_description->setText(errorDescription); + uiWebAuthDialog->m_description->adjustSize(); + uiWebAuthDialog->m_pinGroupBox->setVisible(false); + uiWebAuthDialog->buttonBox->button(QDialogButtonBox::Ok)->setVisible(false); + uiWebAuthDialog->buttonBox->button(QDialogButtonBox::Retry)->setVisible(isVisibleRetry); + if (isVisibleRetry) + uiWebAuthDialog->buttonBox->button(QDialogButtonBox::Retry)->setFocus(); + uiWebAuthDialog->buttonBox->button(QDialogButtonBox::Cancel)->setVisible(true); + uiWebAuthDialog->buttonBox->button(QDialogButtonBox::Cancel)->setText(tr("Close")); + scrollArea->setVisible(false); +} + +void WebAuthDialog::onRetry() +{ + uxRequest->retry(); +} + +void WebAuthDialog::clearSelectAccountButtons() +{ + QList<QAbstractButton *> buttons = buttonGroup->buttons(); + auto itr = buttons.begin(); + while (itr != buttons.end()) { + QAbstractButton *radioButton = *itr; + selectAccountLayout->removeWidget(radioButton); + buttonGroup->removeButton(radioButton); + delete radioButton; + itr++; + } +} diff --git a/examples/webenginewidgets/simplebrowser/webauthdialog.h b/examples/webenginewidgets/simplebrowser/webauthdialog.h new file mode 100644 index 000000000..352bcd0d4 --- /dev/null +++ b/examples/webenginewidgets/simplebrowser/webauthdialog.h @@ -0,0 +1,41 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef WEBAUTHDIALOG_H +#define WEBAUTHDIALOG_H + +#include <QDialog> +#include <QButtonGroup> +#include <QScrollArea> +#include "ui_webauthdialog.h" +#include "qwebenginewebauthuxrequest.h" + +class WebAuthDialog : public QDialog +{ + Q_OBJECT +public: + WebAuthDialog(QWebEngineWebAuthUXRequest *request, QWidget *parent = nullptr); + ~WebAuthDialog(); + + void updateDisplay(); + +private: + QWebEngineWebAuthUXRequest *uxRequest; + QButtonGroup *buttonGroup = nullptr; + QScrollArea *scrollArea = nullptr; + QWidget *selectAccountWidget = nullptr; + QVBoxLayout *selectAccountLayout = nullptr; + + void setupSelectAccountUI(); + void setupCollectPINUI(); + void setupFinishCollectTokenUI(); + void setupErrorUI(); + void onCancelRequest(); + void onRetry(); + void onAcceptRequest(); + void clearSelectAccountButtons(); + + Ui::WebAuthDialog *uiWebAuthDialog; +}; + +#endif // WEBAUTHDIALOG_H diff --git a/examples/webenginewidgets/simplebrowser/webauthdialog.ui b/examples/webenginewidgets/simplebrowser/webauthdialog.ui new file mode 100644 index 000000000..c8a0456d6 --- /dev/null +++ b/examples/webenginewidgets/simplebrowser/webauthdialog.ui @@ -0,0 +1,151 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>WebAuthDialog</class> + <widget class="QDialog" name="WebAuthDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>563</width> + <height>397</height> + </rect> + </property> + <property name="windowTitle"> + <string>Dialog</string> + </property> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="geometry"> + <rect> + <x>20</x> + <y>320</y> + <width>471</width> + <height>32</height> + </rect> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::Retry</set> + </property> + </widget> + <widget class="QLabel" name="m_headingLabel"> + <property name="geometry"> + <rect> + <x>30</x> + <y>20</y> + <width>321</width> + <height>16</height> + </rect> + </property> + <property name="text"> + <string>Heading</string> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + </widget> + <widget class="QLabel" name="m_description"> + <property name="geometry"> + <rect> + <x>30</x> + <y>60</y> + <width>491</width> + <height>31</height> + </rect> + </property> + <property name="text"> + <string>Description</string> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + </widget> + <widget class="QWidget" name="layoutWidget"> + <property name="geometry"> + <rect> + <x>20</x> + <y>100</y> + <width>471</width> + <height>171</height> + </rect> + </property> + <layout class="QVBoxLayout" name="m_mainVerticalLayout"> + <property name="sizeConstraint"> + <enum>QLayout::SetDefaultConstraint</enum> + </property> + <item> + <widget class="QGroupBox" name="m_pinGroupBox"> + <property name="title"> + <string/> + </property> + <property name="flat"> + <bool>true</bool> + </property> + <widget class="QLabel" name="m_pinLabel"> + <property name="geometry"> + <rect> + <x>10</x> + <y>20</y> + <width>58</width> + <height>16</height> + </rect> + </property> + <property name="text"> + <string>PIN</string> + </property> + </widget> + <widget class="QLineEdit" name="m_pinLineEdit"> + <property name="geometry"> + <rect> + <x>90</x> + <y>20</y> + <width>113</width> + <height>21</height> + </rect> + </property> + </widget> + <widget class="QLabel" name="m_confirmPinLabel"> + <property name="geometry"> + <rect> + <x>10</x> + <y>50</y> + <width>81</width> + <height>16</height> + </rect> + </property> + <property name="text"> + <string>Confirm PIN</string> + </property> + </widget> + <widget class="QLineEdit" name="m_confirmPinLineEdit"> + <property name="geometry"> + <rect> + <x>90</x> + <y>50</y> + <width>113</width> + <height>21</height> + </rect> + </property> + </widget> + <widget class="QLabel" name="m_pinEntryErrorLabel"> + <property name="geometry"> + <rect> + <x>10</x> + <y>80</y> + <width>441</width> + <height>16</height> + </rect> + </property> + <property name="text"> + <string>TextLabel</string> + </property> + </widget> + </widget> + </item> + </layout> + </widget> + </widget> + <resources/> + <connections/> +</ui> diff --git a/examples/webenginewidgets/simplebrowser/webview.cpp b/examples/webenginewidgets/simplebrowser/webview.cpp index e024f9126..a47cb23a3 100644 --- a/examples/webenginewidgets/simplebrowser/webview.cpp +++ b/examples/webenginewidgets/simplebrowser/webview.cpp @@ -9,6 +9,7 @@ #include "webview.h" #include "ui_certificateerrordialog.h" #include "ui_passworddialog.h" +#include "webauthdialog.h" #include <QContextMenuEvent> #include <QDebug> #include <QMenu> @@ -98,6 +99,8 @@ void WebView::setPage(WebPage *page) &WebView::handleProxyAuthenticationRequired); disconnect(oldPage, &QWebEnginePage::registerProtocolHandlerRequested, this, &WebView::handleRegisterProtocolHandlerRequested); + disconnect(oldPage, &QWebEnginePage::webAuthUXRequested, this, + &WebView::handleWebAuthUXRequested); #if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0) disconnect(oldPage, &QWebEnginePage::fileSystemAccessRequested, this, &WebView::handleFileSystemAccessRequested); @@ -121,6 +124,7 @@ void WebView::setPage(WebPage *page) connect(page, &QWebEnginePage::fileSystemAccessRequested, this, &WebView::handleFileSystemAccessRequested); #endif + connect(page, &QWebEnginePage::webAuthUXRequested, this, &WebView::handleWebAuthUXRequested); } int WebView::loadProgress() const @@ -292,6 +296,32 @@ void WebView::handleProxyAuthenticationRequired(const QUrl &, QAuthenticator *au } } +void WebView::handleWebAuthUXRequested(QWebEngineWebAuthUXRequest *request) +{ + if (m_authDialog) + delete m_authDialog; + + m_authDialog = new WebAuthDialog(request, window()); + m_authDialog->setModal(false); + m_authDialog->setWindowFlags(m_authDialog->windowFlags() & ~Qt::WindowContextHelpButtonHint); + + connect(request, &QWebEngineWebAuthUXRequest::stateChanged, this, &WebView::onStateChanged); + m_authDialog->show(); +} + +void WebView::onStateChanged(QWebEngineWebAuthUXRequest::WebAuthUXState state) +{ + if (QWebEngineWebAuthUXRequest::Completed == state + || QWebEngineWebAuthUXRequest::Cancelled == state) { + if (m_authDialog) { + delete m_authDialog; + m_authDialog = nullptr; + } + } else { + m_authDialog->updateDisplay(); + } +} + //! [registerProtocolHandlerRequested] void WebView::handleRegisterProtocolHandlerRequested( QWebEngineRegisterProtocolHandlerRequest request) diff --git a/examples/webenginewidgets/simplebrowser/webview.h b/examples/webenginewidgets/simplebrowser/webview.h index 41bc04ac0..bb4b1f2ad 100644 --- a/examples/webenginewidgets/simplebrowser/webview.h +++ b/examples/webenginewidgets/simplebrowser/webview.h @@ -12,8 +12,10 @@ #endif #include <QWebEnginePage> #include <QWebEngineRegisterProtocolHandlerRequest> +#include <QWebEngineWebAuthUXRequest> class WebPage; +class WebAuthDialog; class WebView : public QWebEngineView { @@ -45,13 +47,16 @@ private slots: void handleRegisterProtocolHandlerRequested(QWebEngineRegisterProtocolHandlerRequest request); #if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0) void handleFileSystemAccessRequested(QWebEngineFileSystemAccessRequest request); + void handleWebAuthUXRequested(QWebEngineWebAuthUXRequest *request); #endif private: void createWebActionTrigger(QWebEnginePage *page, QWebEnginePage::WebAction); + void onStateChanged(QWebEngineWebAuthUXRequest::WebAuthUXState state); private: int m_loadProgress = 100; + WebAuthDialog *m_authDialog = nullptr; }; #endif |