En esta página

WebEngine Widgets Ejemplo de navegador de permisos

Demuestra cómo gestionar las solicitudes de permisos del sitio web y administrar los permisos existentes.

Navegador de permisos con página web que muestra las secciones de portapapeles, notificaciones y fuentes a la izquierda y el panel de permisos a la derecha con opciones de concesión y supresión.

Permission Browser muestra cómo utilizar la clase QWebEnginePermission para gestionar los permisos del sitio web. El ejemplo incluye código para gestionar las solicitudes de permisos entrantes, así como para modificar los permisos ya existentes. También se muestran los efectos de las diferentes políticas de persistencia de permisos definidas en la clase QWebEngineProfile.

Ejecución del ejemplo

Para ejecutar el ejemplo desde Qt Creatorabra el modo Welcome y seleccione el ejemplo de Examples. Para más información, consulte Qt Creator: Tutorial: Construir y ejecutar.

Definiciones de clases

MainWindow

La clase MainWindow hereda de QMainWindow. En su interior, declaramos un puntero de conveniencia a QVBoxLayout que presentará los widgets utilizados para manipular permisos individuales, así como otro puntero de conveniencia al widget que muestra la solicitud de permiso pendiente en ese momento. También declaramos un QWebEngineView, que se utilizará para mostrar el contenido real de la página web.

class MainWindow : public QMainWindow, public Ui_MainWindow
{
    Q_OBJECT
public:
    explicit MainWindow(const QUrl &url);
    ~MainWindow();

private slots:
    void handlePermissionRequested(QWebEnginePermission permission);
    void handleUrlChanged(const QUrl &url);

    void handlePermissionModified(PermissionWidget *widget);
    void handleDeleteAllClicked();
    void handleNewClicked();
    void handleRefreshClicked();
    void handleBackClicked();
    void handleForwardClicked();
    void handlePolicyComboBoxIndexChanged(int);

private:
    bool containsPermission(const QWebEnginePermission &permission);
    PermissionWidget *createPermissionWidget(const QWebEnginePermission &permission);
    void loadStoredPermissions();

    QVBoxLayout *m_layout;
    QWebEngineProfile *m_profile;
    QWebEngineView *m_webview;
    PermissionWidget *m_pendingWidget;
};

El resto del diseño de la aplicación está definido dentro de mainwindow.ui, y fue creado usando Qt Creator en modo Design. MainWindow es una clase hija de Ui_MainWindow, que es una clase C++ generada en tiempo de compilación a partir de las definiciones encontradas dentro de mainwindow.ui.

PermissionWidget y PermissionDialog

La clase PermissionWidget define un widget correspondiente a una única instancia de QWebEnginePermission. Para mayor comodidad, el objeto QWebEnginePermission se almacena en su interior. El propio widget tiene controles para conceder, denegar o eliminar el permiso; todo esto se define dentro de PermissionWidget.ui.

class PermissionWidget : public QWidget, public Ui_PermissionWidget
{
    Q_OBJECT
public:
    PermissionWidget(const QWebEnginePermission &permission, QWidget *parent = nullptr);

    QWebEnginePermission m_permission;

signals:
    void permissionModified(PermissionWidget *widget);

private:
    void updateState();
};

Al hacer clic en el botón "Nuevo" de la interfaz de usuario de la ventana principal, aparecerá una ventana emergente que permitirá al usuario conceder previamente el permiso a un origen conocido. Esa ventana emergente está definida por la clase PermissionDialog:

class PermissionDialog : public QDialog, public Ui_PermissionDialog
{
    Q_OBJECT
public:
    PermissionDialog(const QWebEngineProfile *profile, QWidget *parent = nullptr);
    QWebEnginePermission permission() const;

private:
    const QWebEngineProfile *m_profile;
};

Gestión de solicitudes de permiso entrantes

Cada vez que un sitio web utiliza una API que podría comprometer la privacidad del usuario, se espera que el navegador le muestre un mensaje pidiéndole que conceda o deniegue el permiso. El ejemplo PermissionBrowser tiene una sección dedicada en la parte inferior derecha, que se rellena con un PermissionWidget cada vez que esto sucede.

El PermissionWidget muestra el origen del permiso, el QWebEnginePermission::PermissionType solicitado, así como el estado actual de ese permiso. También tiene botones para conceder y denegar el permiso. Dado que el estado del permiso se recuerda (por defecto), el botón de borrar permite al usuario eliminar el permiso del almacenamiento subyacente.

Para conseguir todo esto, primero conectamos la señal QWebEnginePage's permissionRequested a la ranura MainWindow's handlePermissionRequested:

    connect(m_webview->page(), &QWebEnginePage::permissionRequested, this, &MainWindow::handlePermissionRequested);

El controlador de la señal es relativamente sencillo: intenta crear una instancia PermissionWidget para el objeto QWebEnginePermission proporcionado y, si lo consigue, conecta ese widget al QFrame designado para los permisos pendientes. También nos suscribimos a la señal permissionModified de PermissionWidget para poder mover posteriormente el PermissionWidget de la parte inferior derecha a la lista de widgets existentes más arriba.

void MainWindow::handlePermissionRequested(QWebEnginePermission permission)
{
    PermissionWidget *widget = createPermissionWidget(permission);
    if (widget) {
        m_pendingFrame->layout()->addWidget(widget);
        connect(widget, &PermissionWidget::permissionModified, this, &MainWindow::handlePermissionModified);

        if (m_pendingWidget)
            m_pendingWidget->deleteLater();

        m_pendingWidget = widget;
    }
}

Sólo creamos un nuevo PermissionWidget si no tenemos ya uno existente:

PermissionWidget *MainWindow::createPermissionWidget(const QWebEnginePermission &permission)
{
    if (containsPermission(permission))
        return nullptr;

    return new PermissionWidget(permission, this);
}

Modificar un permiso y mostrarlo al usuario

La interfaz QWebEnginePermission proporciona las funciones grant() y deny(), que son todo lo que se necesita para cambiar el estado de un permiso. Si la aplicación necesita olvidarse de un permiso, utilizamos la función reset().

Dentro del constructor PermissionWidget, enganchamos esas funciones a la señal clicked de los botones, para poder ejecutar la funcionalidad relevante en el objeto QWebEnginePermission.

Cada vez que se pulsa un botón, emitimos la señal permissionModified, que MainWindow utiliza para saber cuándo tiene que mover el widget de la parte inferior derecha a la lista de permisos existentes. También nos aseguramos de llamar a updateState(), que se encarga de las actualizaciones visuales del widget. Cuando se pulsa el botón de eliminar, también nos aseguramos de marcar el widget para su eliminación, ya que sólo queremos mostrar los permisos existentes al usuario.

PermissionWidget::PermissionWidget(const QWebEnginePermission &permission, QWidget *parent)
    : QWidget(parent)
    , m_permission(permission)
{
    setupUi(this);
    connect(m_deleteButton, &QPushButton::clicked, [this]() {
        m_permission.reset();
        emit permissionModified(this);
        deleteLater();
    });

    connect(m_grantButton, &QPushButton::clicked, [this]() {
        m_permission.grant();
        updateState();
        emit permissionModified(this);
    });

    connect(m_denyButton, &QPushButton::clicked, [this]() {
        m_permission.deny();
        updateState();
        emit permissionModified(this);
    });

    updateState();
}

La función updateState() muestra al usuario los datos suministrados por QWebEnginePermission. También se asegura de que, cuando un permiso está en el estado QWebEnginePermission::Invalid, los botones para concederlo o denegarlo están desactivados.

void PermissionWidget::updateState()
{
    switch (m_permission.state()) {
    case QWebEnginePermission::State::Invalid:
        m_stateLabel->setText("<font color='gray'>Invalid</font>");
        m_grantButton->setEnabled(false);
        m_denyButton->setEnabled(false);
        break;
    case QWebEnginePermission::State::Ask:
        m_stateLabel->setText("<font color='yellow'>Waiting for response</font>");
        break;
    case QWebEnginePermission::State::Granted:
        m_stateLabel->setText("<font color='green'>Granted</font>");
        break;
    case QWebEnginePermission::State::Denied:
        m_stateLabel->setText("<font color='red'>Denied</font>");
        break;
    }

    m_typeLabel->setText(QMetaEnum::fromType<QWebEnginePermission::PermissionType>().valueToKey((quint8)m_permission.permissionType()));
    m_originLabel->setText(m_permission.origin().toDisplayString());
}

Cuando se concede o deniega un permiso pendiente, queremos mover el widget asociado a la lista anterior, que contiene todos los permisos existentes actualmente. Hacemos esto en el espacio MainWindow::handlePermissionModified.

void MainWindow::handlePermissionModified(PermissionWidget *widget)
{
    if (!m_pendingWidget || m_pendingWidget != widget)
        return;

    m_pendingFrame->layout()->removeWidget(widget);
    m_pendingWidget = nullptr;

    if (!QWebEnginePermission::isPersistent(widget->m_permission.permissionType())
        || widget->m_permission.state() == QWebEnginePermission::State::Ask
        || m_profile->persistentPermissionsPolicy() == QWebEngineProfile::PersistentPermissionsPolicy::AskEveryTime) {

        widget->deleteLater();
        return;
    }

    m_layout->insertWidget(0, widget);
}

En particular, sólo hacemos esto en los casos en los que sabemos que el permiso es recordado; algunos PermissionTypes no son persistentes, lo que significa que requieren que se muestre una solicitud de permiso al usuario cada vez que se utilizan. También excluimos los permisos con un estado QWebEnginePermission::Ask, que indica que el permiso era reset(), y no añadimos nada a la lista de permisos existentes cuando QWebEngineProfile::persistentPermissionsPolicy se establece en AskEveryTime.

Nota: Consulta la documentación de QWebEnginePermission::PermissionType para ver qué PermissionTypes son persistentes.

Visualización y modificación de permisos existentes

Por defecto, los permisos se almacenan en disco y se recuperan de nuevo al iniciar la aplicación. Para obtener una lista de todos los permisos existentes en el sitio web, llamamos a QWebEngineProfile::listAllPermissions():

void MainWindow::loadStoredPermissions()
{
    QList<QWebEnginePermission> permissionsList = m_profile->listAllPermissions();
    for (QWebEnginePermission &permission : permissionsList) {
        PermissionWidget *widget = createPermissionWidget(permission);
        if (widget)
            m_layout->insertWidget(0, widget);
    }
}

Para cada permiso de la lista, simplemente construimos un nuevo PermissionWidget, y lo añadimos a la lista de la parte derecha de la pantalla. Los permisos existentes se modifican utilizando exactamente la misma API que los pendientes.

Permisos pendientes

Algunos permisos pueden concederse por adelantado, siempre que se conozcan el origen y el tipo de permiso. Al hacer clic en el botón "Nuevo" en la parte superior derecha se creará un cuadro de diálogo emergente que le permitirá hacer precisamente eso. El diálogo está implementado por la clase PermissionDialog:

PermissionDialog::PermissionDialog(const QWebEngineProfile *profile, QWidget *parent)
    : QDialog(parent), m_profile(profile)
{
    setupUi(this);

    auto metaEnum = QMetaEnum::fromType<QWebEnginePermission::PermissionType>();
    for (int i = 0; i < metaEnum.keyCount(); ++i) {
        auto permissionType = QWebEnginePermission::PermissionType(metaEnum.value(i));
        if (QWebEnginePermission::isPersistent(permissionType))
            m_permissionTypeComboBox->addItem(metaEnum.key(i), QVariant::fromValue(permissionType));
    }
}

Rellenamos QComboBox utilizando el tipo QMetaEnum asociado a QWebEnginePermission::PermissionType. Nos aseguramos de filtrar los tipos de permiso no persistentes, ya que no es posible preconcederlos.

Mostramos el diálogo y añadimos el PermissionWidget resultante en la interfaz de usuario dentro del espacio MainWindow::handleNewClicked. El nuevo permiso se gestiona de la misma forma que si lo solicitara un sitio web: llamando a handlePermissionRequested().

void MainWindow::handleNewClicked()
{
    PermissionDialog dialog(m_profile);
    if (dialog.exec() == QDialog::Accepted) {
        handlePermissionRequested(dialog.permission());
    }
}

Cambiar la política de persistencia de permisos

Por defecto, los permisos se almacenan en disco para cada QWebEngineProfile con nombre, y en memoria para cada sin nombre. Normalmente, esta configuración no se cambiará en tiempo de ejecución, pero este ejemplo explora los efectos de cada opción.

  • QWebEngineProfile::StoreOnDisk es el valor predeterminado, y garantiza que cualquier permiso que se haya concedido en la ejecución actual de la aplicación se volverá a cargar en el siguiente inicio. Sólo es necesario conceder un permiso una vez, y los usos posteriores de la API que desencadenó la solicitud se concederán automáticamente, hasta que la aplicación llame a QWebEnginePermission::reset().
  • QWebEngineProfile::StoreInMemory Tiene el mismo comportamiento que el anterior, excepto que los permisos se destruirán al salir de la aplicación y no se guardarán en disco.
  • QWebEngineProfile::AskEveryTime se asegura de que los permisos nunca sean recordados, y todos actúan como si no fueran persistentes. Así, cada vez que una API web necesite un permiso, se mostrará un nuevo aviso al usuario. Esta opción está pensada para compatibilidad con versiones anteriores y aplicaciones que implementan su propio almacenamiento de permisos.

Para garantizar que se muestren al usuario los permisos existentes anteriormente, debemos llamar a QWebEngineProfile::listAllPermissions():

void MainWindow::loadStoredPermissions()
{
    QList<QWebEnginePermission> permissionsList = m_profile->listAllPermissions();
    for (QWebEnginePermission &permission : permissionsList) {
        PermissionWidget *widget = createPermissionWidget(permission);
        if (widget)
            m_layout->insertWidget(0, widget);
    }
}

Esto se hace una vez en el inicio, así como cada vez que el usuario cambia la política de la QComboBox desde la parte superior derecha.

void MainWindow::handlePolicyComboBoxIndexChanged(int)
{
    auto policy =
            m_policyComboBox->currentData().value<QWebEngineProfile::PersistentPermissionsPolicy>();
    if (policy == m_profile->persistentPermissionsPolicy())
        return;

    for (int i = m_layout->count() - 1; i >= 0; i--) {
        PermissionWidget *widget = qobject_cast<PermissionWidget *>(m_layout->itemAt(i)->widget());
        if (!widget)
            continue;

        widget->deleteLater();
    }

    m_profile->setPersistentPermissionsPolicy(policy);
    loadStoredPermissions();
}

Proyecto de ejemplo @ code.qt.io

© 2026 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.