I have a "CanActivate" checking on my web service if the user is logged in.
The "CanActivate" return Observable. The only worry is that I would need to recover the value of this boolean in order to be able to adapt my view if the user is connected or not without redoing a 2nd request...
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);
}
Thank you for your help
I had a similar issue, and solved it using a authentication service, where I instead uses a BehaviorSubject, to track the member authentication state:
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 implementation:
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 saves the url request, so the member is redirected correctly after login.
Then you only need to call your authentication API if the _cachedMember is null. Remember to set _cachedMember to null on logout and inform subjects.
logout() {
this._cachedMember = null;
this._member$.next(this._cachedMember );
}
[EDIT] I found an issue with the earlier solution. Its a good idea to wrap the authorizing mechanism in an observable, and do a null check if the _member$ subject is assign. Then the initial state is valid if navigating directly to a route which is guarded!
If you want to save some data when you make a request on your backend to make sure a user is connected, instead of making the HTTP request in the guard
, create a service
that does this request (which is a good practice anyway and you should do that whether or not you want to save a request).
That said, in your service
, which is a singleton, you can simply map
your call (which results into an Observable
) and save the value in your 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 in 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 doesn't have to be more complex than that :)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.