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