且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何将 Ext JS 用于基于角色的应用程序

更新时间:2023-11-24 19:46:58

我必须在我目前开发的应用程序中解决类似问题,但权限基于用户国家/地区.

I had to solve a similar problem in an application that I currently developed, but permissions are based on user country.

我知道您已经这样做了,但为了任何人阅读的利益重申,权限应该始终在服务器端实现,而 JavaScript 安全始终是次要的.这是因为任何有半脑的人都可以使用书签或 Firebug 来执行任意 JavaScript 并规避您的客户端安全性.

I know you already are, but just to reiterate for the benefit of anyone reading, permissions should always be implemented on the server side and JavaScript security is always secondary. This is because anyone with half a brain can use either a bookmarklet or Firebug to execute arbitrary JavaScript and circumvent your client-side security.

我发现有几种方法可以做到这一点,但有两种方法是最合理的.无论采用哪种方法,都需要考虑两件事:1)服务器使用什么 JavaScript 以及如何避免提供不必要的逻辑,以及 2)如何避免执行用户无法使用的逻辑.

I've found that there are several ways to do this, but there are two approaches in particular that are the most sane. Regardless of the approach, there are two things to consider: 1) what JavaScript to server and how to avoid serving unnecessary logic, and 2) how to avoid executing logic that is not available to the user.

  1. 我的应用程序中的所有小部件都是通过 dojo.require 延迟加载的,因此无需担心不必要地包含不适用于用户的 JavaScript.我对 ExtJs 库不是很熟悉,但据我所知,它没有提供类似的方法;但是,同步 ajax 调用后跟 eval 是必不可少的.在任何情况下,在这种方法中,重要的是组件功能不会跨越不同的文件(而且,这通常是好的设计).每个文件都应该是自己的类,用于控制特定的小部件或其他 UI 元素.

  1. All widgets in my application are lazy loaded via dojo.require, so there was no need to worry about the unnecessary inclusion of JavaScript that wasn't applicable to the user. I am not deeply familiar with the ExtJs library, but as far as I have seen, it doesn't supply a comparable method; however, it is essential a synchronous ajax call followed by an eval. In any case, in this method it is important that component functionality doesn't cross-cut through different files (also, this is generally good design). Each file should be its own class that controls a specific widget or other UI element.

然后我在服务器生成的 JavaScript 配置类中设置权限.然后可以在整个应用程序中引用这个类,了解什么是允许的,什么是不允许的.

I then set permissions in a server generated JavaScript config class. This class can then be referenced throughout the application for what is and what is not allowed.

例如,以下方法控制对全局控件可用的大多数小部件的访问.

For example, the following method controlled access to most of the widgets that were available from global controls.

com.project.frontController.prototype.init = function(widgets) {
   var permissions = com.project.config.permissions;

   // For each widget in the controller
   for ( var i=0, l=widgets.length; i<l; ++i ) {
       // If access is restricted to the widget (by id), then disable it.
       if ( !permissions[ widgets[i].id ] {
           com.project.util.disable(widgets[i].btnAccessNode);
       }
       // Otherwise, leave it enabled and connect the necessary event handlers.
       else {
           // connect an onclick handler or whatever is required for the widget
       }
   }
};

配置看起来像:

com.project.config.permissions = {
    "widgetAbc": {
        btnAccessNode:     "#some-css-selector",
        otherWidgetConfig: "etc"
    },
    "widgetXyz": {
        btnAccessNode:     "div.some-css-selector"
    }
};

编译和功能检查:

  1. 有些应用程序会将其所有 JavaScript 编译成一个文件,然后将其提供给客户端.如果您的应用程序执行这样的操作,并且您可以设法动态执行此操作,则可以在服务器端确定所有必需的 JS 再提供服务.当然,这会产生一些开销;但是,您可以按角色缓存编译版本.如果角色很少,那么这个缓存可以很容易地准备好,只需包含一个特定的脚本.

  1. Some applications will compile all of its JavaScript into one file, and then serve it to the client. If your application does such a thing, and you can manage to do this dynamically, all necessary JS can be determined on the server-side before it is served. Of course, this will accrue some overhead; however, you can cache compiled versions by role. If the roles are few, then this cache can be easily primed and it's just a matter of including one specific script.

由于只有允许的 JavaScript 可用,因此您只需在尝试执行所需的类/函数之前检测它是否可用即可进行权限检查.

Since only the allowed JavaScript will be available, simply detecting if the required class/function is available before attempting to execute it is all you need to do for your permissions check.

例如,您的脚本包含可能如下所示:

For example, you script inclusion may look like this:

<script type="text/javascript" src="/js/compiler.php?role=moderator"></script>

您的功能检查将是这样的:

And your functionality check would be something like this:

com.project.frontController.prototype.init = function(widgets) {
   // For each widget in the controller
   for ( var i=0, l=widgets.length; i<l; ++i ) {
       // If the widget controller doesn't exist, disable it.
       if ( !com.project.util.widgetExists[ widgets[i].id ] {
           com.project.util.disable(widgets[i].btnAccessNode);
       }
       // Otherwise, leave it enabled and connect the necessary event handlers.
       else {
           // connect an onclick handler or whatever is required for the widget
       }
   }
};

com.project.someWidget.prototype.launchOtherWidget = function() {
    if ( typeof otherWidget != "undefined" ) {
        (new otherWidget()).open();
    }
};

请注意,这两种方法在实现上非常相似.我认为在两者之间做出决定的***方法是考虑代码库的大小、可用于即时编译的工具以及缓存那些基于角色的编译包.对于我的项目,不仅编译器在环境中不可用,而且代码库很大(1.3mb 膨胀/296kb 默认加上 dojo 库),这是不可接受的,因为客户端对保持低应用程序负载更感兴趣次.

Notice that both methods are very similar in implementation. I would say the best way to make a determination between the two is to consider the size of your codebase, the tools available to you for compiling on the fly, and caching those role-based, compiled packages. For my project, not only was a compiler not available in the environment, but the code base was large (1.3mb inflated/296kb defaulted plus the dojo library), which wasn't acceptable as the client was more interested in maintaining low application load times.