我要啦免费统计

Load Dojo Modules Conditionally when using Spring Security

Scenario

In a JSP page, I want to load different Dojo modules defined in separate .js files according to the authorization roles determined by Spring Security.

At first glance, it seems that dojo/has fits my need. dojo/has provides feature detection with extensible API. So we can assign difference classes to the body element based on user’s authorization roles, and then define a test for dojo/has, that adds features based on whether the body contains a certain class or not.

Then, we can use

1
2
3
4
require(["dojo/has!feature?package/module:package/other"], function(featureModule){
// If feature is true, package/module loaded
// If feature is false, package/other loaded
});

to load modules conditionally.

However, a vital drawback of this method is that the check is done on the client side, which means the user can modify the body class on the client side to bypass the security mechanism and load the module that the user is not authorized to load. Thus Spring Security taglib is used instead in order to archive the goal.

Create Dojo modules

We want to create our own Dojo modules. The global function define is used instead of require.

In the following example, we also want to do something on a already declared dojo widget. In order to do this, we need to obtain a reference of the object by using dijit/registry.

Note: do not use dojo/domReady in the parameters of the define function to deffer the execution of the code until all the elements are ready. Instead, use dojo/ready to do the check. The reason for this is that dojo.ready not only checks if the DOM is ready, but also check if all outstanding require() calls have been resolved, and other registered functions with a higher priority have completed.

At first, I did not notice this, and my registry.byId would return an undefined object.

dojo_module_A.js
1
2
3
4
5
6
7
8
9
10
define(["dojo/ready", "dijit/registry"], function(ready, registry){
return{
load: function(){
ready(function(){
var widget = registry.byId("widget-id");
// do something with widget
})
}
}
});

Require the Defined Modules in Dojo Loader

If we want to keep our modules in the folder /resources/scripts, we need to declare the package location in the packages property of dojoConfig, such as below:

example.jsp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<script>
var dojoConfig = {
async: true,
parseOnLoad: false,
has: {
"dojo-firebug": true,
"dojo-debug-messages": true
},
packages: [{
name: "scripts",
location: location.pathname.replace(/\/[^/]*$/, '') + '/resources/scripts'
}]
};
</script>
<script src="https://ajax.googleapis.com/ajax/libs/dojo/1.10.0/dojo/dojo.js"></script>

The packages attribute should contain a list of explicitly defined packages. A package object contains four properties:

  • name: (string) the name of the package

  • location: (string) the path to the directory where the package resides

  • main: (optional; string) the module identifier implied when a module identifier that is equivalent to just the package name is given; defaults to “main”. (e.g. “dojo” => “dojo/main”)

  • packageMap: (optional; object) a map that allows package names to be aliased to other locations for this particular package only. See Relocating Module Namespaces for more information. (Note: this feature is currently exclusive to the Dojo loader.)

Spring Security in the View Layer using Taglib

To secure view layer of applications, Spring Security has its own taglib which provides basic support for accessing security information and applying security constraints in JSPs. To use security features in JSP files, we need to add the following tag library declaration:

example.jsp
1
<%@ taglib uri="http://www.springframework.org/security/tags" prefix="security" %>

You can choose the prefix of your own and you will need to use this prefix in JSP files.

The overall design is: if a user has been granted by Spring Security with the permission ROLE_TYPE_A, the Dojo module dojo_module_A will be loaded. Otherwise, the Dojo module dojo_module_B will be loaded.

Spring Security taglib provides the authorize tag, which is used to determine whether its contents should be evaluated or not. This tag has two flavors, i.e. securing information based on user’s role or securing information based on user’s permission to access a particular URL. Here, we will take the advantage of different user roles.

example.jsp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<sec:authorize access="hasRole('ROLE_TYPE_A')">
<script>
require(["scripts/dojo_module_A"], function(module){
module.load();
});
</script>
</sec:authorizze>
<sec:authorize access="!hasRole('ROLE_TYPE_A')">
<script>
require(["scripts/dojo_module_B"], function(module){
module.load();
});
</script>
</sec:authorize>

Then when user tries to access example.jsp, only the respective module will be loaded based on the user’s authorization, and this is finished on the server side.

If you have any questions, feel free to leave a comment below.