1

Using Asp Core on Angular 4 with the default template from asp core. The guard works, but on page refresh I get unwanted behavior. When refreshing a guarded route it briefly shows my login page when canActivate is true. Image below shows this behavior. Notice on refresh the screen flashes red (my login page).

enter image description here

Steps to reproduce issue:

  1. Create project with dotnet new angular
  2. Run the dotnet restore and npm install
  3. Add file auth.guard.ts (code below)
  4. Add file auth.service.ts (code below)
  5. Add login component
  6. Add service and guard to routes in app.modal.shared.ts (code below)
  7. Add login button on home component
  8. Run program and click login button
  9. Navigate to the counter route
  10. Press F5 to refresh, the login page will appear before showing counter route (should not show login page as canActivate should be true)

Please let me know if you wish to see any additional code or if you have any questions. I have been pulling my hair out the past two days trying all kinds of things with Observables, maps and subscriptions with no results. Any help will be greatly appreciated. Thanks in advance!

auth.guard.ts

import { Injectable } from '@angular/core';
import { Router, CanActivate } from '@angular/router'
import { AuthService } from './auth.service';
@Injectable()
export class AuthGuard implements CanActivate {
  constructor(
    private authService: AuthService,
    private router: Router) {
  }
  canActivate() {
    if (!this.authService.isLoggedIn()) {
      this.router.navigate(['/login']);
      return false;
    }
    return true;
  }
}

auth.service.ts

import { Injectable, Inject, PLATFORM_ID } from '@angular/core';
import { Router } from '@angular/router';
import { Response, Headers, RequestOptions } from '@angular/http';
import { isPlatformBrowser, isPlatformServer } from '@angular/common';
import { Observable } from 'rxjs/Rx';
import { BehaviorSubject } from 'rxjs/Rx';
@Injectable()
export class AuthService {
  private baseUrl: string = '';
  private loggedIn = false;
  uid: string | null;
  constructor(
    private router: Router,
    @Inject(PLATFORM_ID) private platformId: Object
  ) {
    if (isPlatformBrowser(this.platformId)) {
      this.loggedIn = !!localStorage.getItem('auth_token');
    }
  }
  login() {
    this.loggedIn = true;
    localStorage.setItem('auth_token', 'test');
  }
  logout() {
    localStorage.removeItem('auth_token');
    localStorage.removeItem('uid');
    window.location.replace('/home'); // redirect as we want all var and obj to reset
  }
  isLoggedIn() {
    return this.loggedIn;
  }
}

app.module.shared.ts

...
RouterModule.forRoot([
    { path: '', redirectTo: 'home', pathMatch: 'full' },
    { path: 'home', component: HomeComponent },
    { path: 'login', component: LoginComponent },
    { path: 'counter', component: CounterComponent, canActivate: [AuthGuard] },
    { path: 'fetch-data', component: FetchDataComponent, canActivate: [AuthGuard] },
    { path: '**', redirectTo: 'home' }
])
...

EDIT: Added gif of issue.

EDIT: Found out this is an issue with server-side prerendering. I am currently looking into how to setup a token storage service and pass this to the server.

David Lee
  • 2,040
  • 17
  • 36
  • Try change result from `auth.guard.ts`, to Observable instead boolean. – Daredzik Oct 03 '17 at 17:52
  • I changed to `canActivate(): Observable` and set the returns to `return Observable.of(false);` (same for true) and still experiencing the same behavior. – David Lee Oct 03 '17 at 17:56
  • Ok, now if u press F5 u have login screen, now if u go to `/home` and now go to `/counter` still redirect to `/login` ? – Daredzik Oct 03 '17 at 18:03
  • @Daredzik I added a gif to the question, hopefully it clears anything up on the issue. – David Lee Oct 03 '17 at 18:27
  • Hmmm, can you try change your auth service. Let's change `isLoggedIn()` add `localstorage.getitem` here and return as observable. Here also link: https://stackoverflow.com/a/42701376/4092201 – Daredzik Oct 03 '17 at 18:48
  • @Daredzik I think I have figured out what is causing the issue. The dotnet angular template comes with server-side prerendering and when I remove the `asp-prerender-module="ClientApp/dist/main-server"` from the app in the `Index.cshtml` page the guard acts normally. Not sure what the work around is as I would like to have server-side prerendering enabled. – David Lee Oct 03 '17 at 19:45
  • @Daredzik have you found any solution for this? – Jainam Shah Nov 22 '19 at 05:26

0 Answers0