Grafana-web可视只读/自助服务终端模式,可集成到企业应用程序中

时间:2016-11-10 07:56:55

标签: grafana

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

有些观点是:

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

由于Grafana没有这样的东西,我打算将其加载到iframe中并将XSS加载到其中以隐藏按钮(两个UI都将从同一个域加载)。

1 个答案:

答案 0 :(得分:1)

我完全理解并接受Torkel和Grafana团队的决定,不要只在前端设置只读模式作为"邪恶"用户可以轻松查询周围的后端,因此从安全角度来看,他们是对的。

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

警告:为了确保你得到它,这是一个grafana-web的视觉样式,并没有提供任何安全性,一个"邪恶"用户仍然可以访问所有内容。

所以我的实施方式如下:

  • 所有用户都在Grafana中编辑权限(按钮仅隐藏前端)
  • 将grafana-web加载到iframe
  • iframe要么有一个掩码(一个也可以移动iframe我们的视图或者制作如果完全透明)
  • 在iframe DOMContentLoaded处理程序中,我们在iframe文档上注册MutationObserver,以便在使用Rafael Weinstein提供的令人惊叹的Mutation Summary库时将按钮添加到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中运行的版本)进行了测试。

升级grafana后,会尝试更新github页面中的代码。

可以在我的github页面上使用iframe中的play.grafana.org找到完整的示例,并且play.grafana不在您的域中,可以通过启动它来禁用Chrome中的同源策略:

google-chrome --disable-web-security --user-data-dir