Security News
The Push to Ban Ransom Payments Is Gaining Momentum
Ransomware costs victims an estimated $30 billion per year and has gotten so out of control that global support for banning payments is gaining momentum.
ui-router.grant
Advanced tools
Readme
The UI Router Grant module provides a quick and easy solution for adding test(s) to your ui-router states. For example if you wanted to restrict certain states to authenticated users, ui-router.grant is a quick solve. For more details check out the demo or the getting started section.
This documentation assumes you are comfortable working with angular-ui-router. The grant module was built specifically to work with ui-router's resolve functionality.
$ bower install angular-ui-router-grant
from your console$ npm install ui-router.grant
from your consoleThe module takes advantage of Array.prototype.forEach() and Array.prototype.some() which are unavailable in older browsers. The good news is both these methods can be easily polyfilled.
Once you have successfully installed the module your setup should look similar to this:
<!doctype html>
<html ng-app="myApp">
<head>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.12/angular.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.13/angular-ui-router.min.js"></script>
<script src="js/angular-ui-rotuer-grant.js"></script>
<script>
var app = angular.module('app', ['ui.router.grant']);
</script>
...
</head>
<body>
...
</body>
</html>
The ui.router.grant module is primarily made up off two core angular services grant
and GrantTest
. To better explain how the grant module works I'll demo an example. Let's assume that we have an app with the following ui-router states:
$stateProvider
.state('member-only', {
url: '/members',
templateUrl: 'partials/only-member.html'
})
.state('admin-only', {
url: '/admins',
templateUrl: 'partials/only-admin.html'
})
.state('except-member', {
url: '/no-members',
templateUrl: 'partials/except-member.html'
})
.state('combined', {
url: '/combined',
templateUrl: 'partials/combined.html'
})
.state('denied', {
url: '/denied',
templateUrl: 'partials/denied.html'
})
The following states are currently accessible by any user, but we would like to enforce the following rules:
member-only
can only be accessed by membersadmin-only
can only be accessed by adminsexcept-member
can be accessed by anyone except memberscombined
can only be accessed by someone who is both a member and admindenied
will be where users are redirected when failing a grant testCreating tests with the grant module is easy. In order to enforce the above rules we need to create tests that will determine if someone is a member or admin.
app.module('app', ['ui.router.grant'])
.run(function(grant, memberService, adminService) {
/**
* A test is very simple and takes two params.
* @param {String} testName - A unique id for the test.
* @param {Function} validate - A function that will validate whether your test passes or fails.
*/
grant.addTest('member', function() {
// getUser is an async request to a RESTful API that returns a promise.
// If the member exists promise will resolve and test will pass.
// If the member doesn't exist promise will reject and test will fail.
return memberService.getUser();
});
grant.addTest('admin', function() {
// You can also return a synchronous value.
// If the returned value evaluates to true test will pass.
// If the returned value evaluates to false test will fail.
return isAdmin;
});
});
Use the grant.only(options)
method to allow state access to only those user's that pass the provided grant tests.
The options param can either be a single test object, or an array of test objects if there are multiple tests. A valid test object requires two properties test (test name) and state (ui-router state the user will be redirected to if the test fails) properties.
.state('admin-only', {
url: '/admins',
templateUrl: 'partials/only-admin.html',
resolve: {
admin: function(grant) {
return grant.only({test: 'admin', state: 'denied'});
}
}
})
Use the grant.except(options)
method to restrict state access to all user's that pass the provided grant tests. Essentially this does the oppisite of grant.only
.
.state('except-member', {
url: '/no-members',
templateUrl: 'partials/except-member.html',
resolve: {
admin: function(grant) {
return grant.except({test: 'member', state: 'denied'});
}
}
})
Both grant.only
and grant.except
allow you to provide multiple grant tests when needed. In the example's combined
state we want only user's that pass both the member and admin grant tests to have access. Before a state with multiple grant tests can resolve both tests will need to pass - It is all or nothing.
It's important to note that grant's with multiple asynchronous tests may not resolve/reject in the order they are listed. For example if a user fails both the member and admin tests, but the admin test rejects before the member test. The user will actually be redirected to the admin fail state even though it is listed second.
.state('combined', {
url: '/combined',
templateUrl: 'partials/combined.html'
controller: function(combined) {
// combined will be an array of the values returned from grant.only
// combined[0] - value returned from member test
// combined[1] - value returned from admin test
var newUser = combined[0];
var newAdmin = combined[1];
},
resolve: {
combined: function(grant) {
return grant.only([
{test: 'member', state: 'denied'},
{test: 'admin', state: 'home'}
]);
}
}
})
Instead of protecting individual states you can also protect parent states, which means that protection will propagate down to all child states. In the below example by applying the grant member test to the parent
state, we have also protected parent.child1
and parent.child2
states with the same test.
.state('parent', {
abstract: true,
template: '<div ui-view></div>',
resolve: {
member: function(grant) {
return grant.only({test: 'member', state: 'denied'});
}
}
})
.state('parent.child1', {
url: '/nested',
templateUrl: 'partials/nested.html'
})
.state('parent.child2', {
url: '/nested',
templateUrl: 'partials/nested.html'
})
You can also still apply separate grant tests to child states as well. Using the above example again we will now apply an admin grant test to the parent.child1
state.
.state('parent', {
abstract: true,
template: '<div ui-view></div>',
resolve: {
member: function(grant) {
return grant.only({test: 'member', state: 'denied'});
}
}
})
.state('parent.child1', {
url: '/nested',
templateUrl: 'partials/nested.html',
resolve: {
admin: function(grant, member) {
// by injecting the member resolve key from the 'parent' state
// we ensure that the member grant test will be completed before
// the admin test executes in the 'parent.child1' state.
return grant.only({test: 'admin', state: 'denied'});
}
}
})
There may be instances where your grant tests need acces to the state's ui-router $stateParams object. This can be done by passing the stateParams object to your grant.only
or grant.except
method. This will ensure that any of the included tests have access to the $stateParams object.
.state('member-only', {
url: '/members/:memberId',
templateUrl: 'partials/only-member.html',
resolve: {
member: function(grant, $stateParams) {
return grant.only({test: 'member', state: 'denied'}, $stateParams);
}
}
})
grant.addTest('member', function() {
// You now have access to $stateParams through
// the GrantTest instance stateParams property
var memberId = this.stateParams.memberId;
return memberService.getUser(memberId);
});
Add a new test to the grant service that can be used by grant.only
and grant.except
Param | Type | Details |
---|---|---|
testName | String | A unique identifier for your test. |
validateFunction | Function | A function that should return a promise or value. If the test has passed the promise should resolve, and if value it should return truthy. The opposite should occur if the test fails. |
Check to see if the test already exists in grant service.
Param | Type | Details |
---|---|---|
testName | String | A unique identifier for your test. |
Returns Boolean Will return true if test exists, and false if it does not.
Ensure that ONLY those user's that pass the provided tests gain access to the ui-router state.
Param | Type | Details |
---|---|---|
tests | Object/Array | A single test object or an array of multiple test objects |
stateParams (optional) | Object | A reference to ui-router's $stateParams object |
Ensure that all user's EXCEPT those that pass the provided tests gain access to the ui-router state.
Param | Type | Details |
---|---|---|
tests | Object/Array | A single test object or an array of multiple test objects |
stateParams (optional) | Object | A reference to ui-router's $stateParams object |
The test object(s) grant.only
and grant.except
require should be in the following format.
single test:
{test: 'testName', state: 'stateName'}
multiple tests:[{test: 'testName', state: 'stateName'}, {test: 'testName2', state: 'stateName2'}]
FAQs
Protect your ui-router routes with the easy to use grant module.
We found that ui-router.grant demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Ransomware costs victims an estimated $30 billion per year and has gotten so out of control that global support for banning payments is gaining momentum.
Application Security
New SEC disclosure rules aim to enforce timely cyber incident reporting, but fear of job loss and inadequate resources lead to significant underreporting.
Security News
The Python Software Foundation has secured a 5-year sponsorship from Fastly that supports PSF's activities and events, most notably the security and reliability of the Python Package Index (PyPI).