I have a bit of a pickle.
I am using Route guard (implementing CanActivate
interface) to check if user is granted access to particular route:
const routes: Routes = [
{
path: '',
component: DashboardViewComponent
},
{
path: 'login',
component: LoginViewComponent
},
{
path: 'protected/foo',
component: FooViewComponent,
data: {allowAccessTo: ['Administrator']},
canActivate: [RouteGuard]
},
{
path: '**',
component: ErrorNotFoundViewComponent
}
];
Now it works great in protecting the '/protected/foo' route from activating, but I would like to tell the user that route he is trying to access is forbidden (similar to 403 Forbidden you may get from server).
The problem:
How do I show the user this special error view without redirecting him to error route which seams to be the preferred option by so many sources I have found?
And how do I still use my RouteGuard
without actually loading the forbidden route, because if I check access inside my FooViewComponent
and display different view it kind of defeats point of having RouteGuard
in the first place.
Ideally I would like to have my RouteGuard
not only returning false in canActivate()
method, but also replace component completely with say ErrorForbiddenViewComponent
. But I have no idea how to do it, or is it event possible. Any alternatives?
This is how my route guard looks now:
import {Injectable} from '@angular/core';
import {Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot} from '@angular/router';
import {AuthService} from '../services/auth.service';
@Injectable()
export class RouteGuard implements CanActivate {
constructor(
private router: Router,
private auth: AuthService
) {}
canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
const { auth, router } = this;
const { allowAccessTo } = next.data;
const identity = auth.getIdentity();
if (
identity &&
allowAccessTo.indexOf(identity.role)
) {
// all good, proceed with activating route
return true;
}
if (identity) {
// TODO show ErrorForbiddenViewComponent instead of redirecting
console.log('403 Forbidden >>', next);
}
else {
// not logged in: redirect to login page with the return url
const [returnUrl, returnQueryParams] = state.url.split('?');
console.log('401 Unauthorised >>', returnUrl, returnQueryParams, next);
router.navigate(['/login'], {queryParams: {returnUrl, returnQueryParams}});
}
return false;
}
}
So I am just preventing route from loading, but I am not redirecting. I only redirect non logged visitors to login route.
Reasoning:
Does anyone have some kind of solution for this? I also wonder how come that after Angular 2+ being around for so long nobody had this kind of situation before? Everybody is just ok with redirecting?
Also keep in mind that although I am currently using the FooViewComponent
synchronously, that may change in future!
Now here if we want to prevent navigation of an unauthorized user we can use CanActivate Guard, that will do the job but also download the module. Now to control the navigation as well as prevent downloading of that module we can use CanLoad Guard.
CanActivateChild - Decides if children routes of a route can be activated. CanDeactivate - Decides if a route can be deactivated.
CanActivate basically answers the question: “Does the user have access to this route?” We use this guard to prevent access to users who are not authorized to access a route.
Angular offers us the ultimate solution to address this problem. That is called AuthGuard. AuthGuard is used to protect the routes from unauthorized access.
I had once worked on the similar problem.
Sharing my stackblitz poc where I have created -
/auth
route is provided with PermissionGuardService
guard)The guard is evaluating the user type and handling the redirection / error accordingly.
The use cases are -
shows a toast with log in message
)shows a toast with unauthorised message
)show a toast with success messaage
)I have stored the user in local storage.
EDIT - DEMO
Let me know if you need a special handling in it and I will update the code base.
Cheers!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With