README
Ember Permissions
Permission management for Ember applications.
Table of Contents
Introduction
@bagaar/ember-permissions is an addon that allows you to manage and validate permissions for the current session. It also allows you to define required permissions per route so you can protect specific parts of your application. Instead of using a mixin to protect your routes, the addon allows you to define the required permissions per route in a single file. Whenever a transition occurs that is not allowed, a route-access-denied event is triggered so you can decide how to handle the denied transition.
Compatibility
- Ember.js v3.16 or above
- Ember CLI v3.16 or above
- Node.js v12 or above
Installation
ember install @bagaar/ember-permissions
Usage
1. Setting up User Session Permissions
First, we need to let the permissions service know which permissions are available for the current session. In the example below, we're using an additional service to request the permissions from an API. Afterwards, we pass along the permissions to the permissions service via the setPermissions method.
// app/routes/application.js
import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';
export default class ApplicationRoute extends Route {
@service('api') apiService;
@service('permissions') permissionsService;
async beforeModel() {
const permissions = await this.apiService.request('/permissions');
this.permissionsService.setPermissions(permissions);
}
}
Once the permissions are set, we can start checking their presence. In the example below, we use the has-permissions helper to conditionally render a delete button based on the presence of the delete-users permission.
{{! app/templates/users/index.hbs }}
{{#if (has-permissions "delete-users")}}
<button type="button">
Delete User
</button>
{{/if}}
NOTE: If you need to validate permissions inside a JavaScript file, you can use the
hasPermissionsmethod on thepermissionsservice instead.
2. Setting up Route Permissions
Start off with defining the required permissions per route. You're free to define them where you want, as long as the format is the same as shown below.
// app/route-permissions.js
export default {
'users.index': ['view-users'],
'users.create': ['create-users'],
'users.edit': ['edit-users'],
};
Next, edit the application route from step 1 as follows:
- Use the
setRoutePermissionsmethod to pass along the required permissions per route to thepermissionsservice. - Handle the
route-access-deniedevent to determine what to do when a transition is denied. - Call
enableRouteValidation.
// app/routes/application.js
import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';
import routePermissions from 'app-name/route-permissions';
export default class ApplicationRoute extends Route {
@service('api') apiService;
@service('permissions') permissionsService;
async beforeModel() {
const permissions = await this.apiService.request('/permissions');
this.permissionsService.setPermissions(permissions);
this.permissionsService.setRoutePermissions(routePermissions);
this.permissionsService.on('route-access-denied', ( /* deniedTransition */ ) => {
// Handle the `route-access-denied` event.
// E.g. redirect to a generic error route.
this.transitionTo('error', { error: 'route-access-denied' });
});
this.permissionsService.enableRouteValidation();
}
}
Now each transition will be validated based on the required permissions per route. If a transition is not allowed the route-access-denied event will be triggered.
Since the required permissions per route are now set, we can start checking if routes can be accessed. In the example below, we use the can-access-route helper to do so.
{{! app/components/menu.hbs }}
{{#if (can-access-route "users.index")}}
<li>
<LinkTo @route="users.index">
Users
</LinkTo>
</li>
{{/if}}
NOTE: If you need to validate if a route can be accessed inside a JavaScript file, you can use the
canAccessRoutemethod on thepermissionsservice instead.
Public API
Permissions Service
Methods
setPermissions
Allows you to set the permissions for the current session.
Arguments
An array of permissions.
Returns
/
Example
permissionsService.setPermissions([
'view-users',
'create-users',
'edit-users',
]);
setRoutePermissions
Allows you to set the required permissions per route.
Arguments
An object of which the keys are route names and the values are arrays of required permissions.
Returns
/
Example
permissionsService.setRoutePermissions({
'users.index': ['view-users'],
'users.create': ['create-users'],
'users.edit': ['edit-users'],
});
hasPermissions
Checks if all the provided permissions are available for the current session.
Arguments
An array of permissions.
Returns
Returns true if all the provided permissions are available for the current session, false if otherwise.
Example
permissionsService.hasPermissions([
'view-users',
'create-users',
'edit-users',
]);
canAccessRoute
Checks if the provided route can be accessed.
Arguments
A route's name.
Returns
Returns true if the provided route can be accessed, false if otherwise.
Example
permissionsService.canAccessRoute('users.index');
enableRouteValidation
This will tell the service that it should start validating each transition and confirm that it's allowed based on the required permissions per route. If a transition is not allowed the route-access-denied event will be triggered.
Arguments
/
Returns
/
Example
permissionsService.enableRouteValidation();
Events
route-access-denied
Triggered when a transition occurs that is not allowed.
Parameters
The denied transition.
Example
permissionsService.on('route-access-denied', ( /* deniedTransition */ ) => {
// Handle the `route-access-denied` event.
// E.g. redirect to a generic error route.
routerService.transitionTo('error', { error: 'route-access-denied' });
});
Helpers
has-permissions
Checks if all the provided permissions are available for the current session.
Arguments
Separate permissions.
Returns
Returns true if all the provided permissions are available for the current session, false if otherwise.
Example
{{has-permissions "view-users" "create-users" "edit-users"}}
can-access-route
Checks if the provided route can be accessed.
Arguments
A route's name.
Returns
Returns true if the provided route can be accessed, false if otherwise.
Example
{{can-access-route "users.index"}}
Contributing
See the Contributing guide for details.
License
This project is licensed under the MIT License.
Maintenance
@bagaar/ember-permissions is built and maintained by Bagaar.