0
votes

I created a service for my angular app like so:

export class AuthService {

    public currentUser: Subject<firebase.User> = new Subject();
    public currentUserId: Subject<string> = new Subject();

    constructor(private auth: AngularFireAuth){
        auth.authState.subscribe(r => {
            this.currentUser.next(r);        // the user object
            this.currentUserId.next(r.uid);  // the user id
        });
    }
}

I use this service in my components when routing occurs.

When the user first arrives at a page from their browser, the other components are successfully notified of the authentication changes. However, when a user clicks a link to go to another page, the two observables don't fire and the listening components aren't notified of the authentication state changes. The only way to work is if the user refreshes their browser since they seem to only fire when the user lands on their first page only. After that, I lost the user information and am never informed again.

How can I have the two observables fire every time a page navigation occurs? Or is this even the correct approach to doing this?

2
Does the current user change often and that's why this needs to be a notification? Otherwise, it would seem that a simple property would suffice?DeborahK
No it's pretty constant. If I do a property though, then retrieving the user information would be complicated though since I have to check the property first, and if it's null, then subscribe to the Subejcts. Doing this for every component is annoying.AskYous
Have you seen the example here: angularfirebase.com/lessons/…DeborahK

2 Answers

0
votes

I don't know the reason to use it during routing... I used CanLoad in my last project

//Inside Auth Service
public authStates = new BehaviorSubject<AuthState>(this.getAuthState());

private getAuthState(): AuthState {
  const token = this.getToken();
  if (token || !tokenHelper.isTokenExpired(token)) {
    const payload: JwtPayload = jwt(token);
    return {
      authenticated: true,
      id: payload.uid,
      role: payload.type
    };
  }
  return {
    authenticated: false
  };
}

canLoad(route: Route): Observable<boolean> {
  const roles: string[] = route.data.roles;
  return this.authState.pipe(
    take(1),
    map((authState: AuthState) => {
      if (
        authState.authenticated &&
        authState.role &&
        roles.includes(authState.role)
      ) {
        return true;
      } else if (!authState.authenticated && roles.includes("guest")) {
        return true;
      }
      this.toastrService.error(
        "You have not sufficient permissions for that action"
      );
      return false;
    })
  );
}

// In routes module
const appRoutes: Routes = [
  {
    path: environment.settings.user.backendPath,
    loadChildren: "app/user/user.module#UserModule",
    canLoad: [AuthService],
    data: {
      roles: ["user"]
    }
  },
]

I also used canActivate, canActivateChild and custom written auth directives such as *hideForRoles, *showForRoles, authOnly etc...

0
votes

This was the solution thanks to @DeborahK's link to angularfirebase.com:

export class AuthService {
    public currentUser: Observable<UserDoc>;

    constructor(
        public afAuth: AngularFireAuth
    ) {
        this.currentUser = this.afAuth.authState;

        // then other components subscribe to this observable
        // and can run `.id` on the resolved parameter.
    }
}