Yuriy Kovalets
Yuriy Kovalets

Reputation: 11

Problem with CanActivate guards when initialNavigation: 'enabled'

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

Answers (2)

dchang
dchang

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

Anzal Khan
Anzal Khan

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

Related Questions