Authorization middleware for Node.js and the Javascript platform in general
It leverages the authorization library permit-authorize
See wiki for an overview.
Most important sections:
AuthorizeMw = require 'authorize-mw'
The following is a complete example, using LiveScript syntax for a "clearer" picture.
authorize = require 'authorize-mw'
Middleware = require 'middleware' .Middleware
AuthorizeMw = authorize.AuthorizeMw
Permit = authorize.Permit
permit-for = authorize.permit-for
Book = require './models/book'
book = new Book title: title
GuestUser = require './models/users/guest'
guest-user = new GuestUser name: 'unknown'
guest-permit = permit-for(GuestPermit, 'guest books',
match: (access) ->
@matches(access).user role: 'guest'
rules:
ctx:
area:
guest: ->
@ucan 'publish', 'Paper'
admin: ->
@ucannot 'publish', 'Paper'
read: ->
@ucan 'read' 'Book'
write: ->
@ucan 'write' 'Book'
default: ->
@ucan 'read' 'any'
)
basic-authorize-mws = new AuthorizeMw current-user: guest-user
auth-middleware = new Middleware 'model' data: books.hello
auth-middleware.use authorize: basic-authorize-mws
read-books-request =
action : 'read'
collection : 'books'
allowed = auth-middleware.run read-books-request
Please note that the above middleware setup can be expanded with validator, decorator and marshaller middleware for a complete stack. This is especially useful when combined and used with a Real Time sync server.
Same example as above in pure Javascript:
var authorize, Middleware, AuthorizeMw, Permit,
permitFor, Book, book, GuestUser, guestUser,
guestPermit, basicAuthorizeMws,
authMiddleware, readBooksRequest, allowed;
AuthorizeMw = require('authorize-mw');
authorize = require('permit-authorize');
Middleware = require('middleware').Middleware;
Permit = authorize.Permit;
permitFor = authorize.permitFor;
Book = require 'models/book'
book = new Book({
title: title
});
GuestUser = require 'models/users/guest'
guestUser = new GuestUser({
name: 'unknown'
});
guestPermit = permitFor('guest', {
match: function(access){
return this.matches(access).user({role: 'guest'});
},
rules: {
ctx: {
area: {
guest: function(){
return this.ucan('publish', 'Paper');
},
admin: function(){
return this.ucannot('publish', 'Paper');
}
}
},
read: function(){
return this.ucan('read', 'Book');
},
write: function(){
return this.ucan('write', 'Book');
},
'default': function(){
return this.ucan('read', 'any');
}
}
});
basicAuthorizeMws = new AuthorizeMw({
currentUser: guestUser
});
authMiddleware = new Middleware('model', {
data: books.hello
});
authMiddleware.use({
authorize: basicAuthorizeMws
});
readBooksRequest = {
action: 'read',
collection: 'books'
};
allowed = authMiddleware.run(readBooksRequest);
You can also run with the user as part of the run context
publish-book-request =
user : guest-user
action : 'publish'
data : book
allowed = auth-middleware.run publish-book-request
or you can use model
instead of collection
publish-book-request =
user : guest-user
action : 'publish'
model : `book`
All tests are passing :)
Why LiveScript?
Since it is faster/easier to develop the basic functionality. We can always later refactor the code to use something else.
Why classes and not prototypical inheritance?
In one word "Productivity!", a class is a convenient abstraction for encapsulation.
Feel free to fork this project and provide a version without classes if that is a MUST for you...
Run mocha
on all files in test folder
Just run all test like this:
$ mocha
To execute individual test, do like this:
$ mocha test/authorize-mw/permit_test.js
The library istanbul is used for code coverage.
See code-coverage-with-mocha for use with mocha.
npm install -g istanbul
istanbul cover _mocha -- -R spec
open coverage/lcov-report/index.html
$ instanbul cover _mocha
To measure coverage of individual test:
$ instanbul cover _mocha test/authorize-mw/permit_test.js
Please help improve this project, suggest improvements, add better tests etc. ;)
MIT License Copyright 2014-2015 Kristian Mandrup