Angular 2 - CanActivate Observable get value after subscription

I have a "CanActivate" check on my web service if the user is logged in.

Return "CanActivate" Observable. The only concern is that I will need to restore the value of this boolean to be able to adapt my view if the user is connected or not, without redoing the second query ...

canActivate(): Observable<boolean>|boolean {
    return this.connected();
  }
public connected() : Observable<boolean>{
    return this.http.get(this.connectedUrl,{ withCredentials: true })
      .map(this.extractBoolean)
      .catch(this.handleError);
  }

      

thanks for the help

+3


source to share


2 answers


I had a similar problem and solved it using an Authentication Service where I instead use a BehaviorSubject to track the authentication state of an item:

public member: Subject<Member> = new Subject<Member>();

private _cachedMember: Member;
private _member$: BehaviorSubject<Member>;

constructor(private _http: Http, private _router: Router) {         
}

get member$(): Observable<Member> {     
    if (!this._cachedMember) {          
        this.getAuthorizedMember().subscribe();
    }
    return this._member$.asObservable();
}

private getAuthorizedMember(): Observable<Member> {
     // call your auth API and set _cachedMember accordingly:
     this._cachedMember = member;
     this._member$.next(this._cachedMember);
}

      

My auth.guard.ts canActivate function:

canActivate(): Observable<boolean> | boolean {

        return this._authService.member$.map(member => {
            if (member) return true;
            else {
                // Set entry url
                var currentUrl: URL = new URL(this._document.location.href);
                this._authService.entryUrl = currentUrl.pathname;

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

}

      



The else statement stores the request for the url, so after login the element is redirected correctly.

Then you only need to call the authentication API if _cachedMember is NULL. Remember to set _cachedMember to null for logout and report objects.

logout() {
    this._cachedMember = null;
    this._member$.next(this._cachedMember );
}

      

[EDIT] I found a problem with an earlier solution. It is a good idea to wrap the authorization mechanism in an observable and perform a null check if the _member $ object is assigned. Then the initial state is valid if you are heading directly to the route that is being guarded!

+1


source


If you want to save some data when you make a request on your server to make sure the user is connected, instead of making an HTTP request in guard

, create service

one that fulfills that request (which is good practice anyway and you should do this if you want to save the query).

However, in yours service

, which is single, you can just map

call your (which results in Observable

) and store the value in service

.

For example:

@Injectable()
export class SomeService {
  private userData: IUserData;

  constructor(private http: Http) { }

  getUserDataIfConnected() {
    this.http.get('http://some-url')
      .map((res: Response) => res.json() as IUserData)
      .map(userData => this.userData = userData)
  }
}

      



Then on your guard:

canActivate(): Observable<boolean> {
  return this.someService.getUserDataIfConnected()
    // if there was no error, we don't care about the result, just return true : The user is connected
    .mapTo(true)
    // if the user wasn't logged, your backend shoud return an HTTP error code in the header
    // and angular HTTP service will throw an error
    .catch(err => return Observable.of(false))
}

      

It shouldn't be any more complicated than this :)

+1


source







All Articles