angular: Render 404 page with CanActivate guard without aborting navigation
I’m submitting a … (check one with “x”)
[ ] bug report => search github for a similar issue or PR before submitting
[X] feature request
[ ] support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question
Background
When a user navigates to a route that requires authentication and they are not authenticated, there’s no way to use a CanActivate
guard to render a 404 component and still update the url to what the user was trying to access.
Current behavior
Let’s say a user navigates to /protected
and is not authenticated. Currently, in the CanActivate
guard, in order to render my 404 component, I would use router.navigate(['404'], { skipLocationChange: true }); return false;
. However, after rendering the 404 component, the url in the address bar is the previous url before the navigation since the navigation was aborted.
Expected behavior
In CanActivate
guard, there should be a way to render the 404 route while still updating the url in the address bar to /protected
.
Minimal reproduction of the problem with instructions
@Injectable()
export class LoggedInGuard implements CanActivate {
constructor(private router: Router, private userService: UserService) {}
canActivate() {
if (this.userService.isLoggedIn) return true;
this.router.navigate(['/404'], { skipLocationChange: true });
return false;
}
}
This code will render a 404 page, but not update the url. I would like it to render 404 and update the url in the address bar to what the user was trying to access.
What is the motivation / use case for changing the behavior? Github does this, for example, if you go to https://github.com/simonxca/webpack-guide, it will render a 404 page even though the repo exists because you’re not authenticated. The motivation is to prevent users from being able to distinguish between a protected from a non-existent page for security.
Please tell us about your environment: Mac OSX Sierra, Node 6.10.3
-
Angular version: 4.1.X
-
Browser: all
-
Language: all
About this issue
- Original URL
- State: closed
- Created 7 years ago
- Reactions: 76
- Comments: 16 (4 by maintainers)
Commits related to this issue
- fix(router): Prevent URL flicker when new navigations cancel ongoing ones This bit of code is problematic for several reasons: 1. AngularJS-specific handling should not exist in core router code if i... — committed to atscott/angular by atscott 3 years ago
- fix(router): Prevent URL flicker when new navigations cancel ongoing ones (#43496) This bit of code is problematic for several reasons: 1. AngularJS-specific handling should not exist in core router ... — committed to angular/angular by atscott 3 years ago
- fix(router): Prevent URL flicker when new navigations cancel ongoing ones (#43496) This bit of code is problematic for several reasons: 1. AngularJS-specific handling should not exist in core router ... — committed to TeriGlover/angular by atscott 3 years ago
- fix(router): Prevent URL flicker when new navigations cancel ongoing ones (#43496) This bit of code is problematic for several reasons: 1. AngularJS-specific handling should not exist in core router ... — committed to TeriGlover/angular by atscott 3 years ago
- feat(router): Add ability to return `UrlTree` with `NavigationBehaviorOptions` from guards Returning `UrlTree` from a guard was a convenient new feature added to the `Router`. However, it does not ha... — committed to atscott/angular by atscott 3 years ago
- feat(router): Add ability to return `UrlTree` with `NavigationBehaviorOptions` from guards Returning `UrlTree` from a guard was a convenient new feature added to the `Router`. However, it does not ha... — committed to atscott/angular by atscott 3 years ago
- feat(router): Add ability to return `UrlTree` with `NavigationBehaviorOptions` from guards Returning `UrlTree` from a guard was a convenient new feature added to the `Router`. However, it does not ha... — committed to atscott/angular by atscott 3 years ago
- feat(router): Add ability to return `UrlTree` with `NavigationBehaviorOptions` from guards Returning `UrlTree` from a guard was a convenient new feature added to the `Router`. However, it does not ha... — committed to atscott/angular by atscott 3 years ago
- feat(router): Add ability to return `UrlTree` with `NavigationBehaviorOptions` from guards Returning `UrlTree` from a guard was a convenient new feature added to the `Router`. However, it does not ha... — committed to atscott/angular by atscott 3 years ago
- feat(router): Add ability to return `UrlTree` with `NavigationBehaviorOptions` from guards Returning `UrlTree` from a guard was a convenient new feature added to the `Router`. However, it does not ha... — committed to atscott/angular by atscott 3 years ago
- feat(router): Add ability to return `UrlTree` with `NavigationBehaviorOptions` from guards Returning `UrlTree` from a guard was a convenient new feature added to the `Router`. However, it does not ha... — committed to atscott/angular by atscott 3 years ago
- feat(router): Add ability to return `UrlTree` with `NavigationBehaviorOptions` from guards Returning `UrlTree` from a guard was a convenient new feature added to the `Router`. However, it does not ha... — committed to atscott/angular by atscott 3 years ago
- feat(router): Add ability to return `UrlTree` with `NavigationBehaviorOptions` from guards Returning `UrlTree` from a guard was a convenient new feature added to the `Router`. However, it does not ha... — committed to atscott/angular by atscott 3 years ago
- feat(router): Add ability to return `UrlTree` with `NavigationBehaviorOptions` from guards Returning `UrlTree` from a guard was a convenient new feature added to the `Router`. However, it does not ha... — committed to atscott/angular by atscott 3 years ago
- feat(router): Add ability to return `UrlTree` with `NavigationBehaviorOptions` from guards Returning `UrlTree` from a guard was a convenient new feature added to the `Router`. However, it does not ha... — committed to atscott/angular by atscott 3 years ago
- feat(router): Add ability to return `UrlTree` with `NavigationBehaviorOptions` from guards Returning `UrlTree` from a guard was a convenient new feature added to the `Router`. However, it does not ha... — committed to atscott/angular by atscott 3 years ago
- feat(router): Add ability to return `UrlTree` with `NavigationBehaviorOptions` from guards Returning `UrlTree` from a guard was a convenient new feature added to the `Router`. However, it does not ha... — committed to atscott/angular by atscott 3 years ago
- feat(router): Add ability to return `UrlTree` with `NavigationBehaviorOptions` from guards Returning `UrlTree` from a guard was a convenient new feature added to the `Router`. However, it does not ha... — committed to atscott/angular by atscott 3 years ago
- feat(router): Add ability to return `UrlTree` with `NavigationBehaviorOptions` from guards Returning `UrlTree` from a guard was a convenient new feature added to the `Router`. However, it does not ha... — committed to atscott/angular by atscott 3 years ago
- feat(router): Add ability to return `UrlTree` with `NavigationBehaviorOptions` from guards Returning `UrlTree` from a guard was a convenient new feature added to the `Router`. However, it does not ha... — committed to atscott/angular by atscott 3 years ago
Are there any updates on this? This seems like it would be a common request, but I cannot find much on it.
The use case for me is to have pages only certain users can access. I already don’t render the pages in the navigation bar when they don’t have them, but when they manually navigate to the certain pages, I want it to act as if the page does not exist, even though it does. Right now, I got it showing the 404, but the URL just goes back to the root.
Imperfect workaround for anyone else landing here. You still get a small blink of the previous route since you’re returning
canActivate
false and then the url is replaced.In my case this was good enough.
/no-access
in this example) is never in the history due toskipLocationChange: true
/no-access
component insteadlocation.replaceState docs
Guard
Receiving Component for
/no-access
routeWould be helpful if this were possible in other guards as well – for example I have a Resolve guard which does a server lookup for route data, which can result in a 404 or authentication error as well, and I’d like to be able to display a 404 or 401 error without aborting navigation.
Is there any update on this? Since it’s a very common case for all projects.
This is related with #16981. A workarround could be the proposed by @ccondrup on this comment https://github.com/angular/angular/issues/16981#issuecomment-549330207.
@JackMorrissey’s workaround does the trick, but using
location.replaceState
breaks back navigation as no new state had been pushed to the History stack since the guard returned true. Usinglocation.go
(which is basically justpushState
) solves that. The URL still blinks when no route had been previously activated though.My Brothers and my Sisters I have solution about this.
When you said “false” to canActivate, you told the Router, “do not change the Url”.
If you need to keep that Url, canActivate is not the right tool for you.
You can use a route Resolve. Inside the Resolve, return either your object you want, or undefined.
Now let your component load. The one that requires the object from the Resolve.
Inside that component you gonna have an onInit who is listening to ActivatedRoute.data.
If you found your object you’re looking for inside ActivatedRoute.data, your component can do it’s thing.
Now the best part, in your component who is already loaded, when you found out your ActivatedRoute.data didn’t have your object because the Resolver set it to undefined. Now you can just use router.navigate to your 404 with skipLocationChange true.
You permitted navigation, because you wanted the Url to stay. But you show the 404 route silently. Your component needs to know how to do that.