There are some problems when using the deep linker with nav guards and authentication in general.
For example, the recommended way to implement an auth guard for a page is via ionViewCanEnter(). Often, data must be requested for a page that depends on, say, a current auth session, which may need to be asynchronously created on startup. The ionic team obviously anticipated cases like this and made ionViewCanEnter() return a promise. But that means I have to request my session-dependent page data in ionViewWillEnter(), which is called every time a page is displayed. What if I only want to request it once in ionViewDidLoad() or constructor?
Besides the timing issues, implementing guards in ionViewCanEnter is problematic when I have 30 pages in an app and 28 of them require authentication. Is there not something in Ionic like Angularās guard functions that could 1) be declaratively added to a route configuration and 2) not require instantiation and loading of the page before finding out if itās OK to go there? Angularās routing system is great at this stuff.
I ended up creating my own router that handles auth redirects, but the deep linker doesnāt have any good hooks to determine when itās trying to load a page and the router doesnāt expose viewCanEnter/viewCanLeave events as it does with the other lifecyle events, so Iāve had to make a page base class to handle auth guards under the covers and cooperatively work with the custom router to handle redirection. This is a hack. A few well-placed hooks would solve some big issues.
I have no inside information, but based on what Iāve read on GitHub, thereās a lot of work going on behind the scenes to improve Ionic routing, and an update is coming āsoon.ā Iāve intentionally stayed away from guards and deep links because Iām waiting for this to happen first. What Iāve done is prioritized construction of things that donāt depend on routing.
There are still a lot of security issues in Ionic in general. Securing API keys, for example, is a problem that still lacks a solution that I am comfortable with. I consider it the reality of working with early technology.
Perhaps Iām not understanding what youāre saying here, but I think āsecuring API keysā in the sense of āmake it so that somebody that has the app binary canāt extract secrets out of itā is impossible.
The problem is that however hard you make it for a black hat to extract the secret is however hard it is for your app to do it in order to do its normal business. I do my best to design things so that there is no need for hardcoded secrets in apps.
design things so that there is no need for hardcoded secrets in apps.
Iāve come to that conclusion as well, though Iām sure my attempts in that direction are primitive compared to yours. But, more or less, Iām trying to ensure that the client side is hard to phish, and the server side is hard to crack. The OP wants the client side to help with āhard to crack,ā and I donāt think Ionic is ready for that strategy yet.
thereās a lot of work going on behind the scenes to improve Ionic routing
Happy to hear this is still evolving. That was also a minor reason for pushing this all into a couple of self-contained classes. It will be much easier to refactor later than if I had guards strewn about in all my pages. The recommended guard method is not SoC-friendly.
I was having the same issues, and while this doesnāt solve any of the items around late checking of the āguardā (loading lazy modules even when they should have been guarded, or constructing the component before determining if it should even be allowed), it does help me from duplicating navCtrl setRoot all over the place, and lets me declare required roles for guard and ovrride the redirect route if needed:
Create a custom decorator:
export const Role = (requiredRole: string, redirectRoute = 'about-page') => {
return (target: any) => {
target.prototype.ionViewCanEnter = function() {
if(this.navCtrl === undefined) {
throw new Error("@Role requires the target component to have a property called 'navCtrl' that is the injected NavController");
}else {
//do the role check stuff here to see if the desired role is good
//just navigating to default and returning false to test
this.navCtrl.setRoot(redirectRoute);
return false;
}
}
}
};
Then use it on your container components like:
@Role(āAdminā)
or @Role(āInstructorā, āspecial-loginā)
And make sure you inject navCtrl:NavController into the component.
The code above is not complete obviously, and could be expanded to do more. I just dropped it in to test if it would work.
@barryrowe I tested your solution, with this implementation which is great, you have the same problem with breaking change. You can not do setRoot if youreturn false. Did you found a workaround for that? Or did you never upgrade ionic-angular package?
I havenāt run into what youāre describing, but we havenāt been using this approach extensively. We are on ionic-angular v3.5.3.
Since the routing path in Ionic is still up in the air, we have kind of ignored this issue right now. The app weāre currently working on is quite small, and luckily we can handle roles at the API layer on the server, so our users might see a page, but just have empty data for now. Itās far from ideal, but we didnāt feel it warranted the headaches of trying to find out a hack for proper route control at this stage, when it may be solved by the time we get to it.
I will say though, that LazyLoading and DeepLinking in general seems very flaky, and could cause us to drop Ionic all together and just go with angular + angular-material, and hand-roll things like cordova service wrappers.
We are in a big project and have not enough human resources to rollback our decision to use ionic. Ionic is great but there are a lot of problems with LazyLoading, Navigation and URLS.
Ionic4 would all do this better, but I think there is still a long way for that.
Thanks for the heads up. What version introduced the breaking change?
From our experience, it seems Ionic is perfect for small, focused applications, but anything larger it seems some of the design decisions really start to get in your way (as we see with navigation/lazyloading). It seems that larger more complex applications just hadnāt been a real target for the platform, and it shows.
And I wrote there it is from 3.5.0, which app-scripts do you use?
I created a new very simple empty project with 3 pages, if you click to page two you should be redirected to page3 but, if you return false, this does not work, if you return true it work.