Grafana web可视只读/信息亭模式,用于在企业应用程序中集成

Grafana web可视只读/信息亭模式,用于在企业应用程序中集成,grafana,Grafana,在项目中要求将grafana web完全集成到企业应用程序中 其中一些要点是: 不显示grafana菜单(仪表板通过API读取并集成在应用程序菜单中) 为用户隐藏游乐场按钮(即使grafana提供了只读模式,也只能防止保存而不能使用设置/数据) 对于某些用户,允许编辑模式(添加行、仪表板设置、仪表板保存…) 禁用所有用户的共享 所有这些都是前端的视觉怪癖,安全级别低(邪恶的用户仍然可以绕过隐藏的按钮,这没关系) 通过Enterprise应用程序中的按钮触发的API创建/删除仪表板 由于Gra

在项目中要求将grafana web完全集成到企业应用程序中

其中一些要点是:

  • 不显示grafana菜单(仪表板通过API读取并集成在应用程序菜单中)
  • 为用户隐藏游乐场按钮(即使grafana提供了只读模式,也只能防止保存而不能使用设置/数据)
  • 对于某些用户,允许编辑模式(添加行、仪表板设置、仪表板保存…)
  • 禁用所有用户的共享
  • 所有这些都是前端的视觉怪癖,安全级别低(邪恶的用户仍然可以绕过隐藏的按钮,这没关系)
  • 通过Enterprise应用程序中的按钮触发的API创建/删除仪表板

由于Grafana没有类似的功能,我想将其加载到iframe中,并将XSS加载到其中以隐藏按钮(两个UI都将从同一个域加载)。

我完全理解并接受Torkel和Grafana团队的决定,即前端不采用只读模式,因为“邪恶”用户可以轻松查询其后端,所以从安全角度来看,他们是对的

但正如您所看到的,一些边缘案例/项目需要这样做,即使只是作为一种视觉上的怪癖

警告:为了确保您明白了,这是grafana web的视觉样式,不提供任何安全性,“邪恶”用户仍然可以访问所有内容。

下面是我如何实现它的:

  • 所有用户在Grafana中都有编辑权限(按钮仅在前端隐藏)
  • 将grafana web加载到iframe中
  • iframe或者有一个遮罩(也可以将iframe移动到我们的视图中,或者使其完全透明)
  • 在iframe DOMContentLoaded处理程序上,我们使用Rafael Weinstein的惊人库在iframe文档上注册一个MutationObserver,以捕获和隐藏添加到DOM中的按钮
  • 在这个阶段隐藏按钮是因为它们已经被渲染,以防观测者注册为延迟(这是与角度渲染的竞争条件)
  • 移除遮罩(将iframe移动到可见区域,制作opac…)
以下是由DOMContentLoaded触发的自定义程序代码:

// Don't forget to load the mutation-summary.js lib

function iframeLoad (iframe) {
    // Disable this if you want users to have access to playground buttons like:
    // add Rows, edit Panels, dashboard settings ...
    readOnlyMode = true;

    // This is the iframe "window"
    var iframe_window = iframe.contentWindow;

    // This is the iframe "document" under which the MutationObserver will look for DOM changes
    var iframe_document = iframe.contentDocument;

    var queries = [{
        // This is the main menu of grafana
        element: '.navbar-brand-btn' 
    },{ 
        // This is the dashboard selection right of the main menu
        element: '.navbar-page-btn' 
    },{ 
        // This is the share button appearing inside the .dashnav-action-icons, we don't want to allow
        // this to anybody, as it's exposes the real url, thus bypassing this code
        element: 'li[ng-show="::dashboardMeta.canShare"]' 
    },{ 
        // This is the dashboard delete button, under dashboard setting button
        element: 'a[ng-click="deleteDashboard();"]' 
    }];


    if ( readOnlyMode ) {
        queries.push({ 
            // This is the three vertical dots button to open the row menu/edit
            element: '.dash-row-menu-grip' 
        });
        queries.push({
            // This is the bottom "+ ADD ROW" button
            element: '.add-row-panel-hint'
        });
        queries.push({
            // This is the share button right of the dashboard menu
            element: '.dashnav-action-icons' 
        });
        queries.push({
            // This is the "Panel" menu triggered by clicking the Panel name
            element: '.panel-menu' 
        });
    }


    var observer;
    observer = new MutationSummary({
        callback: function (changes) {
            changes.forEach(function (change) {
                change.added.forEach(function (el) {
                    iframe_window.angular.element(el).addClass('ng-hide');
                });
            });

            // Normally we disconnect here to free resources, but on new dashboards
            // the buttons will be re-rendered by Angular, so we keep this to block that behaviour
            //observer.disconnect();
        },
        queries: queries,
        rootNode: iframe_document
    });


    // Hide the elements if they are already generated before we registred the Observer
    // is a race condition afterall "Angular rendering" vs "registering the Observer"
    queries.forEach( function (el) {
        if ( iframe_window && iframe_window.angular ) {
            iframe_window.angular.element(el.element).addClass('ng-hide');
        }
    });

    // Remove the mask or move the iframe into view if needed
    // [YOUR CODE HERE]


}

此方法已针对grafana版本4.0.0-1476697633pre1(以及当前运行在play.grafana.org中的版本)进行了测试。

我完全理解并接受Torkel和grafana团队的决定,即不在前端使用只读模式,因为“邪恶”用户可以轻松查询其后端,所以从安全角度来看,他们是对的

但正如您所看到的,一些边缘案例/项目需要这样做,即使只是作为一种视觉上的怪癖

警告:为了确保您明白了,这是grafana web的视觉样式,不提供任何安全性,“邪恶”用户仍然可以访问所有内容。

下面是我如何实现它的:

  • 所有用户在Grafana中都有编辑权限(按钮仅在前端隐藏)
  • 将grafana web加载到iframe中
  • iframe或者有一个遮罩(也可以将iframe移动到我们的视图中,或者使其完全透明)
  • 在iframe DOMContentLoaded处理程序上,我们使用Rafael Weinstein的惊人库在iframe文档上注册一个MutationObserver,以捕获和隐藏添加到DOM中的按钮
  • 在这个阶段隐藏按钮是因为它们已经被渲染,以防观测者注册为延迟(这是与角度渲染的竞争条件)
  • 移除遮罩(将iframe移动到可见区域,制作opac…)
以下是由DOMContentLoaded触发的自定义程序代码:

// Don't forget to load the mutation-summary.js lib

function iframeLoad (iframe) {
    // Disable this if you want users to have access to playground buttons like:
    // add Rows, edit Panels, dashboard settings ...
    readOnlyMode = true;

    // This is the iframe "window"
    var iframe_window = iframe.contentWindow;

    // This is the iframe "document" under which the MutationObserver will look for DOM changes
    var iframe_document = iframe.contentDocument;

    var queries = [{
        // This is the main menu of grafana
        element: '.navbar-brand-btn' 
    },{ 
        // This is the dashboard selection right of the main menu
        element: '.navbar-page-btn' 
    },{ 
        // This is the share button appearing inside the .dashnav-action-icons, we don't want to allow
        // this to anybody, as it's exposes the real url, thus bypassing this code
        element: 'li[ng-show="::dashboardMeta.canShare"]' 
    },{ 
        // This is the dashboard delete button, under dashboard setting button
        element: 'a[ng-click="deleteDashboard();"]' 
    }];


    if ( readOnlyMode ) {
        queries.push({ 
            // This is the three vertical dots button to open the row menu/edit
            element: '.dash-row-menu-grip' 
        });
        queries.push({
            // This is the bottom "+ ADD ROW" button
            element: '.add-row-panel-hint'
        });
        queries.push({
            // This is the share button right of the dashboard menu
            element: '.dashnav-action-icons' 
        });
        queries.push({
            // This is the "Panel" menu triggered by clicking the Panel name
            element: '.panel-menu' 
        });
    }


    var observer;
    observer = new MutationSummary({
        callback: function (changes) {
            changes.forEach(function (change) {
                change.added.forEach(function (el) {
                    iframe_window.angular.element(el).addClass('ng-hide');
                });
            });

            // Normally we disconnect here to free resources, but on new dashboards
            // the buttons will be re-rendered by Angular, so we keep this to block that behaviour
            //observer.disconnect();
        },
        queries: queries,
        rootNode: iframe_document
    });


    // Hide the elements if they are already generated before we registred the Observer
    // is a race condition afterall "Angular rendering" vs "registering the Observer"
    queries.forEach( function (el) {
        if ( iframe_window && iframe_window.angular ) {
            iframe_window.angular.element(el.element).addClass('ng-hide');
        }
    });

    // Remove the mask or move the iframe into view if needed
    // [YOUR CODE HERE]


}
该方法针对grafana版本4.0.0-1476697633pre1(以及当前在play.grafana.org中运行的版本)进行了测试