11# spel2js
22[ ![ Build Status] [ build-image ]] [ build-url ]
3- [ ![ Code GPA] [ gpa-image ]] [ gpa-url ]
43[ ![ Test Coverage] [ coverage-image ]] [ coverage-url ]
54[ ![ Dependency Status] [ depstat-image ]] [ depstat-url ]
65[ ![ Bower Version] [ bower-image ]] [ bower-url ]
76[ ![ NPM version] [ npm-image ]] [ npm-url ]
7+ <!-- [![Code GPA][gpa-image]][gpa-url]
88[![IRC Channel][irc-image]][irc-url]
99[![Gitter][gitter-image]][gitter-url]
10- [ ![ GitTip] [ tip-image ]] [ tip-url ]
10+ [![GitTip][tip-image]][tip-url]-->
1111
1212## About
1313
14- Quick note: the code is a bit rough ATM, a refactor (ES6, Babel) is on the docket and will happen very soon.
15-
1614SpEL2JS is a plugin that will parse Spring Expression Language within a defined context in JavaScript. This is useful
1715in single-page applications where duplication of authorization expressions for UI purposes can lead to inconsistencies.
1816Consider the following simple example:
@@ -26,7 +24,7 @@ Say you are creating a shared to-do list, and you want to allow only the owner o
2624@RequestMapping (' /todolists' )
2725public class ListController {
2826
29- public static final String ADD_LIST_ITEM_PERMISSION = " #toDoList.owner == principal .name" ;
27+ public static final String ADD_LIST_ITEM_PERMISSION = " #toDoList.owner == authentication.details .name" ;
3028 ...
3129
3230 @PreAuthorize (ADD_LIST_ITEM_PERMISSION )
@@ -43,11 +41,11 @@ public class ListController {
4341``` javascript
4442// list-controller.js
4543
46- angular .module (' ToDo' ).controller (' ListController' , [' $http' , ' $scope' , ' $window ' , function ($http , $scope , $window ) {
44+ angular .module (' ToDo' ).controller (' ListController' , [' $http' , ' $scope' , ' SpelService ' , function ($http , $scope , SpelService ) {
4745
48- $http .get (' /todolists/some-way-to-get-the- permissions' ).success (function (permissions ) {
46+ $http .get (' /api/ permissions' ).success (function (permissions ) {
4947 angular .forEach (permissions, function (spelExpression , key ) {
50- $scope .permissions [key] = $window . spelExpressionParser .compile (spelExpression);
48+ $scope .permissions [key] = SpelService .compile (spelExpression);
5149 });
5250 });
5351
@@ -62,7 +60,7 @@ angular.module('ToDo').controller('ListController', ['$http', '$scope', '$window
6260 }
6361
6462 $scope .addListItem = function (list , newListItem ) {
65- if ($scope .permissions .ADD_LIST_ITEM_PERMISSION .eval ($scope . context )) {
63+ if ($scope .permissions .ADD_LIST_ITEM_PERMISSION .eval (SpelService . getContext (), $scope)) {
6664 $http .post (' /todolists/' + list .id + ' /items' , item).success (function () {... });
6765 }
6866 }
@@ -79,7 +77,7 @@ angular.module('ToDo').controller('ListController', ['$http', '$scope', '$window
7977 </li >
8078 <li class =" list-actions" >
8179 <input type =" text" ng-model =" newListItem.text" />
82- <button ng-click =" addListItem(list, newListItem)" ng -if =" permissions.ADD_LIST_ITEM_PERMISSION.eval(context) " >Add</button >
80+ <button ng-click =" addListItem(list, newListItem)" spel -if =" permissions.ADD_LIST_ITEM_PERMISSION" >Add</button >
8381 </li >
8482 ...
8583</div >
@@ -88,40 +86,41 @@ angular.module('ToDo').controller('ListController', ['$http', '$scope', '$window
8886
8987Seems like it might be a lot of work for such a simple piece of functionality; however, what happens when you add role-based
9088permissions as a new feature? If you already have this set up, it's as simple as adding " or hasRole('SuperUser')" to
91- the SpEL, and exposing a minimal projection of the Principal (UserDetails most likely) to Angular (which it probably already
89+ the SpEL, and exposing a minimal projection of the Authentication to the browser or Node app (which it probably already
9290has access to.) Now the UI can always stay in sync with the server-side authorities.
9391
9492This repository was scaffolded with [ generator-microjs] ( https://github.com/daniellmb/generator-microjs ) .
9593
9694## Left to do
9795
98- This is not currently stable enough to release. The following must be done first:
99-
100- - [x] Port the tokenizer to JS
101- - [x] Port the parser to JS
102- - [ ] Implement the evaluator in JS
103- - [x] Primitive Literals
104- - [x] Property references
105- - [x] Compound expressions
106- - [x] Comparisons
107- - [x] Method references
108- - [x] Local variable reference ("#someVar")
109- - [x] Math
110- - [x] Ternary operators
111- - [x] Safe navigation
112- - [ ] Qualified identifiers/Type references
113- - [x] Assignment
114- - [x] Complex literals
115- - [x] Projection/selection
116- - [x] Increment/Decrement
117- - [x] Logical operators (and, or, not)
118- - [ ] Something I probably missed
119- - [ ] Implement common functions (hasPermission(), hasRole(), isAuthenticated(), etc.)
120-
121- Then some (probably separate project) follow-up features:
122-
123- - [ ] AngularJS service
124- - [ ] AngularJS directives (spelShow, spelHide, spelIf, etc.)
96+ This is now in a stable state and will be released as 0.2.0. The following features are tested and working:
97+
98+ - Primitive Literals
99+ - Property references
100+ - Compound expressions
101+ - Comparisons
102+ - Method references
103+ - Local variable reference ("#someVar")
104+ - Math
105+ - Ternary operators
106+ - Safe navigation
107+ - Assignment
108+ - Complex literals
109+ - Projection/selection
110+ - Increment/Decrement
111+ - Logical operators (and, or, not)
112+ - hasRole() (if you use spel2js.StandardContext)
113+
114+ The following are not implemented yet because I'm not sure of the best approach:
115+
116+ - Qualified identifiers/Type references/Bean References
117+ - hasPermission() for custom permission evaluators
118+
119+ There are a few AngularJS directives (I just need to put them on GH):
120+
121+ - spelShow
122+ - spelHide
123+ - spelIf
125124
126125If someone wants to implement a REST-compliant way in Spring to expose the permissions (and maybe the custom
127126PermissionEvaluators) that would be awesome.
@@ -137,7 +136,6 @@ PermissionEvaluators) that would be awesome.
137136All tasks can be run by simply running ` grunt ` or with the ` npm test ` command, or individually:
138137
139138 * ` grunt lint ` will lint source code for syntax errors and anti-patterns.
140- * ` grunt gpa ` will analyze source code against complexity thresholds.
141139 * ` grunt test ` will run the jasmine unit tests against the source code.
142140
143141## License
0 commit comments