NavGuards with ionic-angular 3.5.0 has a breaking change

With the new ionic-angular 3.5.0 and the improvements on new router and lazy loading by Dan (which btw is working better then ever), there is a breaking change on the NavGuards, we use the Guards to check if user has rights to access to Page, but and if not we redirect user to another page.
This we do simple doing this

constructor(public navCtrl: NavController) {}

ionViewCanEnter(): boolean {

     this.navCtrl.setRoot('Page4');
     return false;
}

If we return false to ionViewCanEnter the app will not redirect to Page4, if we return true the redirection is working but naturally also this page which should be blocked is accessing.

We opened already a bug for this, you can see it here.

It seems, this now is by design, okay. But now how can we redirect a user to a new page if user has not enough rights do access page?

What if you tried returning a promise instead of a boolean?

Same thing,

we have to resolve(true) the Promise we can not reject() it. In our app we already using Promise and not boolean, we post the example with boolean because the issue is also there and the could is clearer.

(Just a note: You should comment on the issue that this is now a permanent issue with the release of 3.5.0)

Sorry what do you intend with “now a permanent issue”??
I already opened a issue, but until now no solution and I hope to find here a workaround for this, for us this is a blocking issue.

The issues still talks about “nightly lazyloading build” and shows an ionic info of " Ionic Framework : ionic-angular 3.4.2-201706271925". if this is now a real issue of 3.5.0, you should add that information to the issue.

Okay man, now I understand, thx for the hint!

1 Like

Yesterday Mike told me we have to do the redirection on pushing the page like this:

this.nav.setRoot(pageName)
              .then((permission) => {
                  if (!permission) {
                      this.nav.setRoot('LoginPage');
                  }
              });

This is working but only a part of the solutions, what if you go direct in the browser to the link, you’ll never redirect to the LoginPage, but I think this is a possible scenario, we have and probably also others.

1 Like

I still don’t understand why people want to jump through all these guard hoops instead of just conditionally setting the app component’s rootPage based on whether the user is authenticated or not.

I saw your solution on another post and thought it was a great idea @rapropos. I’m actually going to implement both methods.

The main purpose in my mind is that of an additional layer of security. If someone managed to find a way to open the page (using the console and some jQuery maybe?) there would be another redirect in there path to keep them from getting through to the content.

My logic could be completely flawed here though and i’m curious what you have to say on the matter.

Another key point I thought up, is that all of this changes with deep-linking.

Let’s say a user punches in a url to a specific back-end page. I don’t want to redirect them to the dashboard if they are logged in.

The way I solved this was to have an auth service that controls this.

All app navigation is done via my app.component.ts - all. Anything that might produce navigation just publishes events, and I have an observer in my main app component that knows what to do with them.

What does this mean?

It means my app.component waits to receive the auth event from my auth service. That event tells the app component whether the user is logged in or not, and the app.component can then choose where to send the user. (in practical terms, my auth service just checks a value from local storage [actually indexeddb] and waits for the auth system to validate that that token is still valid)

This also means that landing on any random page makes absolutely no difference - my app.component will not show any page until it has received that auth event. If you land on a random page, you’ll just get redirected away (this is only an issue on the browser - landing like that on-device is not possible. In the case of deep-linking, my app still waits for the auth event before following the deep link). Because of this, my default rootPage is actually a simple splash screen (very simple - so that it loads very fast).

In practice my splash screen is usually shown for under 500ms. It’s nice though, because it gives the app a sense of being responsive, and also allows me the opportunity to debug app startup issues.

I completely agree with @rapropos - I used the NavGuards when I first started with Ionic but found this event + navigate pattern much, much easier to manage.

1 Like

If someone is interested, in Ionic4 we will get angulars router, so in this case navigation will change a lot for us, we can handle routes which also enables lazyloading by default. At the top of the angular router we can still use ionic nav/push function to simulate a mobile navigation.

In this case, when the ionic router is laying on top of angular router also the default Angular guard behavior could work. So you can choose between both and choose the right one for your requirements!