-
Notifications
You must be signed in to change notification settings - Fork 128
Usage with routes
Now you are ready to start working with controlling access to the states of your application. In order to restrict any state ngx-permission rely on angular-route's data
property, reserving key permissions
allowing to define authorization configuration.
Permissions object accepts following properties:
Property | Accepted value |
---|---|
only |
[String |Array |Function ] |
except |
[String |Array |Function ] |
redirectTo |
[String ] |
Property only
:
- is used to explicitly define permission or role that are allowed to access the state
- when used as
String
contains single permission or role - when used as
Array
contains set of permissions and/or roles
Property except
:
- is used to explicitly define permission or role that are denied to access the state
- when used as
String
contains single permission or role - when used as
Array
contains set of permissions and/or roles
🔥 Important
If you combine bothonly
andexcept
properties you have to make sure they are not excluding each other, because denied roles/permissions would not allow access the state for users even if allowed ones would pass them.
In simplest cases you allow users having single role permission to access the state. To achieve that you can pass as String
desired role/permission to only/except property:
You can use except
and only
at the same time;
import { RouterModule, Routes } from '@angular/router';
import { NgModule } from '@angular/core';
import { HomeComponent } from './home/home.component';
import { NgxPermissionsGuard } from 'ngx-permissions';
const appRoutes: Routes = [
{ path: 'home',
component: HomeComponent,
canActivate: [NgxPermissionsGuard],
data: {
permissions: {
only: 'ADMIN'
}
}
},
];
@NgModule({
imports: [
RouterModule.forRoot(appRoutes)
],
exports: [
RouterModule
]
})
export class AppRoutingModule {}
In given case when user is trying to access home
state NgxPermissionsGuard
service is called checking if isAuthorized
permission is valid:
- if permission definition is not found it stops transition
Often several permissions/roles are sufficient to allow/deny user to access the state. Then array value comes in handy:
import { RouterModule, Routes } from '@angular/router';
import { NgModule } from '@angular/core';
import { HomeComponent } from './home/home.component';
import { NgxPermissionsGuard } from 'ngx-permissions';
const appRoutes: Routes = [
{ path: 'home',
component: HomeComponent,
canActivate: [NgxPermissionsGuard],
data: {
permissions: {
only: ['ADMIN', 'MODERATOR'],
except: ['GUEST']
}
}
},
];
@NgModule({
imports: [
RouterModule.forRoot(appRoutes)
],
exports: [
RouterModule
]
})
export class AppRoutingModule {}
When NgxPermissionsGuard
service will be called it would expect user to have either ADMIN
or MODERATOR
permissions to pass him to home
route.
You can find states that would require to verify access dynamically - often depending on parameters.
Let's imagine situation where user want to modify the invoice. We need to check every time if he is allowed to do that on state level. We are gonna use ActivatedRouteSnapshot
and RouterStateSnapshot
object to check weather he is able to do that.
To make AOT compatible you should export function. Below is presented code AOT Compatible
AOT compatible
export function testPermissions(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
if (route.params['id'] === 42) {
return ['MANAGER', "UTILS"]
} else {
return 'ADMIN'
}
}
const appRoutes: Routes = [
{ path: 'dynamic/:id',
component: HomeComponent,
canActivate: [NgxPermissionsGuard],
data: {
permissions: {
only: testPermissions
}
}
}
];
💀 Warning
Below is presented code not AOT compatible
const appRoutes: Routes = [
{ path: 'dynamic/:id',
component: HomeComponent,
canActivate: [NgxPermissionsGuard],
data: {
permissions: {
only: (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => {
if (route.params['id'] === 42) {
return ['MANAGER', "UTILS"]
} else {
return 'ADMIN'
}
}
}
}
}
];
So whenever we try access state with param id = 42
set to true additional check for permission manager and utils
will be made. Otherwise only ADMIN
will be required.
🔥 Important
Notice that function require to always return array or string of roles/permissions in order to work properly.
Property redirectTo:
- when used as
String
defines single redirection rule - when used as
Objects
defines single/multiple redirection rules - when used as
Function
defines dynamic redirection rule(s)
In case you want to redirect to some specific state when user is not authorized pass to redirectTo
path of that route.
import { RouterModule, Routes } from '@angular/router';
import { NgModule } from '@angular/core';
import { HomeComponent } from './home/home.component';
import { NgxPermissionsGuard } from 'ngx-permissions';
const appRoutes: Routes = [
{ path: 'home',
component: HomeComponent,
canActivate: [NgxPermissionsGuard],
data: {
permissions: {
only: ['ADMIN', 'MODERATOR'],
redirectTo: '/another-route'
}
}
},
];
@NgModule({
imports: [
RouterModule.forRoot(appRoutes)
],
exports: [
RouterModule
]
})
export class AppRoutingModule {}
In order to pass additional properties like params use pass redirectTo
as object.
navigationCommands
and navigationExtras
are reserved words it corresponds to parameters passed to router.navigate function
navigate(commands: any[], extras: NavigationExtras): Promise<boolean>
const appRoutes: Routes = [
{ path: 'home',
component: HomeComponent,
canActivate: [NgxPermissionsGuard],
data: {
permissions: {
only: ['ADMIN', 'MODERATOR'],
redirectTo: {
navigationCommands: ['123'],
navigationExtras: {
skipLocationChange: true
}
}
}
},
];
@NgModule({
imports: [
RouterModule.forRoot(appRoutes)
],
exports: [
RouterModule
]
})
In some situation you want to redirect user based on denied permission/role to create redirection strategies. In order to do that you have to create redirection Object
that contain keys representing rejected permissions or roles and values implementing redirection rules.
Redirection rules are represented by following values:
Value type | Return | Usage |
---|---|---|
String |
[String ] |
Simple state transitions |
Object |
[Object ] |
Redirection with custom parameters or options |
Function |
[String |Object ] |
Dynamic properties-based redirection |
💡 Note
Use default property that will handle fallback redirect for not defined permissions.
The simplest example of multiple redirection rules are redirection based on pairs role/permission and state. When user is not granted to access the state will be redirected to agendaList
if missing canReadAgenda
permission or to dashboard
when missing canEditAgenda
. Property default
is reserved for cases when you want handle specific cases leaving default redirection.
const appRoutes: Routes = [
{ path: 'home',
component: HomeComponent,
canActivate: [NgxPermissionsGuard],
data: {
permissions: {
only: ['canReadAgenda','canEditAgenda'],
redirectTo: {
canReadAgenda: 'agendaList',
canEditAgenda: 'dashboard',
default: 'login'
}
}
}
},
];
@NgModule({
imports: [
RouterModule.forRoot(appRoutes)
],
exports: [
RouterModule
]
})
If you need more control over redirection parameters Object
as a value can be used to customise target url navigationCommands
and transition navigationExtras
.
💡 Note
navigationCommands
andnavigationExtras
are reserved words it corresponds to parameters passed to router.navigate functionnavigate(commands: any[], extras: NavigationExtras): Promise<boolean>
const appRoutes: Routes = [
{ path: 'home',
component: HomeComponent,
canActivate: [NgxPermissionsGuard],
data: {
permissions: {
only: ['canEditAgenda'],
redirectTo:
canEditAgenda: {
navigationCommands: 'dashboard',
navigationExtras: {
skipLocationChange: true
}
},
default: 'login'
}
}
}
},
];
@NgModule({
imports: [
RouterModule.forRoot(appRoutes)
],
exports: [
RouterModule
]
})
To present usage redirectTo
as Object
with values as Function
in a state definition agenda
presented below redirection rules are interpreted as:
- when user does not have
canReadAgenda
invoked function returns string representing the state name to which unauthorized user will be redirected - when user does not have
canEditAgenda
invoked function returns object with custom options and params that will be passed along to transiteddashboard
url
const appRoutes: Routes = [
{ path: 'home',
component: HomeComponent,
canActivate: [NgxPermissionsGuard],
data: {
permissions: {
only: ['canReadAgenda','canEditAgenda'],
redirectTo: {
canReadAgenda: (rejectedPermissionName: string, activateRouteSnapshot: ActivatedRouteSnapshot, routeStateSnapshot: RouterStateSnapshot) => {
return 'dashboard';
},
canEditAgenda: (rejectedPermissionName: string, activateRouteSnapshot: ActivatedRouteSnapshot, routeStateSnapshot: RouterStateSnapshot) => {
return {
navigationCommands: ['/dashboard'],
navigationExtras: {
skipLocationChange: true
}
}
},
default: 'login'
}
}
}
},
];
@NgModule({
imports: [
RouterModule.forRoot(appRoutes)
],
exports: [
RouterModule
]
})
🔥 Important
Above code is not AOT compatible to make it AOT compatible extract it to functionnavigationCommands
andnavigationExtras
reserved words. Matching parameter to router.navigate function
export function canReadAgenda(rejectedPermissionName: string, activateRouteSnapshot: ActivatedRouteSnapshot, routeStateSnapshot: RouterStateSnapshot) => {
return 'dashboard';
},
redirectTo: {
canReadAgenda: canReadAgenda
}
Similarly to examples showing defining dynamic access to state redirection can also be defined based on any parameters of ActivatedRouteSnapshot
and RouterStateSnapshot
;
💡 Note
Remember to always return from function state name or object.
const appRoutes: Routes = [
{ path: 'home/:isEditable',
component: HomeComponent,
canActivate: [NgxPermissionsGuard],
data: {
permissions: {
only: ['canReadAgenda','canEditAgenda'],
redirectTo: (rejectedPermissionName: string, activateRouteSnapshot: ActivatedRouteSnapshot, routerStateSnapshot: RouterStateSnapshot) => {
if(activateRouteSnapshot.params['id'] === 42){
return 'login';
} else {
return 'dashboard'
}
}
}
},
];
@NgModule({
imports: [
RouterModule.forRoot(appRoutes)
],
exports: [
RouterModule
]
})
🔥 Important
Above code is not AOT compatible to make it AOT compatible extract it to function
export function redirectToFunc(rejectedPermissionName: string, activateRouteSnapshot: ActivatedRouteSnapshot, routerStateSnapshot: RouterStateSnapshot) => {
if(activateRouteSnapshot.params['id'] === 42){
return 'login';
} else {
return 'dashboard'
}
}
redirectTo: redirectToFunc
default-redirection-configuration-service
Also its possible to set up default redirection in configuration service
this.ngxConfigurationService.defaultRedirectTo = 'login'
or as a function
function loginRedirect(activateRouteSnapshot: ActivatedRouteSnapshot,
routerStateSnapshot: RouterStateSnapshot) {
return 'login';
}
this.ngxConfigurationService.defaultRedirectTo = loginRedirect
NgxPermissionsGuard implements CanActivate interface for examples you can see above
NgxPermissionsGuard implements CanLoad Interface. Functionality is the same as with canActivate
const appRoutes: Routes = [
{
path: 'lazy',
data: {
permissions: {
except: 'ADDDMIN',
}
},
canLoad: [NgxPermissionsGuard],
loadChildren: 'app/lazy-module/lazy-module.module#LazyModule'
},
];
@NgModule({
imports: [
RouterModule.forRoot(appRoutes)
],
exports: [
RouterModule
],
providers: [
// CanDeactivateGuard
]
})
export class AppRoutingModule {}
🔥 Warning
- The only difference if you use as a function the parameter is only 1 and its type of Route
{
path: 'lazy',
data: {
permissions: {
only: (route: Route) => {
//logic here
return ['MANAGER', "UTILS"]
}
}
},
canLoad: [NgxPermissionsGuard],
loadChildren: 'app/lazy-module/lazy-module.module#LazyModule'
},
NgxPermissionsGuard implements CanLoad Interface. Functionality is the same as with canActivate
🔥 Warning
- Need to remember that rules and data you should specify on Child Components not on parent component
const appRoutes: Routes = [
{ path: '',
component: IsolateComponent,
canActivateChild: [NgxPermissionsGuard],
children: [
{
path: 'except-should',
component: AnotherComponent,
data: {
permissions: {
except: 'ADMIN'
}
}
},
{
path: 'only-should',
component: ComeComponent,
data: {
permissions: {
only: 'GUEST'
}
}
},
]
},
];
Thank You for using the library and support 🌟 . HAVE A GREAT DAY!