Reputation: 11
I have angular universal app where part of routes is protected by CanActivate guard, where canActivate method use services to protect the route. But with initialNavigation: "enabled" config my guards didn't work. As I suppose, this issue is faced because of:
The initial navigation starts before the root component is created. The bootstrap is blocked until the initial navigation is complete. ( from angular docs )
The question is: how can I use services in canActivate guard with initialNavigation - enabled?
Upvotes: 1
Views: 2073
Reputation: 1141
I think @Yuriy Kovalets already found his problem.
But for future reference, for anyone who might have similar problem, as I had.
My application was working well until I set initialNavigation: 'enabledBlocking' because of SSR. Pages/routes that didn't have canActivate set still work well, and the application bootstrap. Then if I navigate to another page that have canActivate set it works.
The problem was when I try to enter directly (put the url into the browser) to pages/routes that have canActivate set.
This is my canActivate RouteGuard
@Injectable()
export class SecurityRouteGuard implements CanActivate {
userIsLoggedIn: Observable<boolean>;
constructor(private router: Router, private securityService: SecurityService) {
this.userIsLoggedIn = of(false);
}
canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
let userState = this.securityService.getUserState();
this.userIsLoggedIn = of(userState.isLoggedIn);
return this.userIsLoggedIn.pipe(map(userIsLoggedIn => {
if (userIsLoggedIn) {
return true;
}
else {
sessionStorage.setItem('lastRequiredURL',state.url);
this.securityService.loginUser();
return false;
}
}))
}
}
As one can see, it depends on SecurityService to validate if user is authenticated or not.
What I found out was that this SecurityService wasn't initialized when I set initialNavigation: 'enabledBlocking' and so the user wasn't redirect to login page as should be.
This happen because my SecurityService was initialized at ngOnInit() of my app.component.ts. With initialNavigation: 'enabledBlocking' the navigation and the canActivate runs before app.component.ts.
My solution was to move SecurityService initialization from app.component.ts to APP_INITIALIZER set at app.module.ts like this:
export function appSecurityInitializer(securityService: SecurityService) {
// SecurityService initialization
}
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule.withServerTransition({ appId: 'serverApp' }),
BrowserAnimationsModule,
AppRoutingModule,
ServiceWorkerModule.register('ngsw-worker.js', {
enabled: environment.production,
// Register the ServiceWorker as soon as the app is stable
// or after 30 seconds (whichever comes first).
registrationStrategy: 'registerWhenStable:30000'
}),
CommonAppModule,
SecurityModule
],
providers: [
{
provide: APP_INITIALIZER,
useFactory: appSecurityInitializer,
deps: [SecurityService],
multi: true
},
],
bootstrap: [AppComponent]
})
export class AppModule { }
Upvotes: 1
Reputation: 61
From what you provided, I could only get into a little of data.
I think what you need is to set some routes, to be protected with can activate, and some other without the route guard.
You can do something like this.
{path: 'secure-path', component: 'SomeSecureComponent', canActivate: [AuthGuard]},
{path: 'not-a-secure-path', component: 'SomeNonSecureComponent'},
You can do something like this to get rid of the route guard in the insecure pages, just don't provide them.
If you think I got your question wrong, please let me know, because this is what i understood from the little information you provided.
Upvotes: 0