0

I have the next Angular Guard:

export class AdminGuard implements CanActivate {
  constructor(
    private readonly router: Router,
    private readonly userService: UserService
  ) { }

  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {

      return this.userService.getUserRoles().pipe(
        map(roles => {
          if (roles.admin) {
            return true
          }

          this.router.navigate(['/'])
          return false
        })
      )
  }
}

This is method from the service, which return Observable:

  public getUserRoles(): Observable<any> {
    return this.store.pipe(
      select('user'),
      map(({ roles }) => roles)
    )
  }

And this is works when I navigate between page, but when I directly enter in URL some route, for example 'myapp.com/admin', it returns false automatically and the guard does not work. How to make it work properly?

Volodymyr Humeniuk
  • 3,411
  • 9
  • 35
  • 70
  • i think you've lost the store data after refresh , are you saving the store in localstorage or not? – Fateh Mohamed May 05 '20 at 21:20
  • @FatehMohamed Im not sure this is a good idea save user roles to localstorage. User can just open and localstorage in browser, and he can change admin role to true and then use admin-panel. – Volodymyr Humeniuk May 05 '20 at 21:22
  • sometimes you have too in case of refresh, using https://github.com/btroncone/ngrx-store-localstorage – Fateh Mohamed May 05 '20 at 21:25
  • @VladimirHumeniuk SPA's run in the browser. They are inherently insecure; users can always change the code and data in the browser to do what they want. The only thing you can secure is the backend. You should check user authorization when they submit changes to the server, and not worry about a user hacking the local store; just think of it as convenient UI to show what actions they *should* be able to do against the backend. If a user thwarts local settings to view the admin panel, this should not compromise back end security. – James World May 05 '20 at 23:12

1 Answers1

1

Best guess, when entering the url directly in the browser, you are restarting your application and the store is reset to defaults with no user.

You should rewrite your getUserRoles() method to check if the user has been authenticated before reading roles, and not just read store state. If you are using OAuth2, for example, this would redirect the user to your authentication endpoint passing appropriate state to resume on the myapp.com/admin route once re-authentication handshake is complete and the store is populated.

The specifics of this will very much depend on what authentication approach you are using.

James World
  • 29,019
  • 9
  • 86
  • 120