Reputation: 10384
The call of GetData
from the controller of a component is done too early, I would like it to wait for the end of the identification before triggering.
When the page is loading, there is a call to the server for identification:
return this.http.get<AuthInfo>('.../Auth/login').pipe(
map((authInfo: AuthInfo) => {
// ... authentification completed
return authInfo;
}),
);
Then, from several other components, they will be able to call the server : (with a JWT token previously provided)
this.serviceA.methodB().subscribe(
result => { ... }
)
methodB(): Observable<any> {
return this.http.get<any>('.../Data/GetData').pipe(
map(result => {
...
return result;
}),
);
}
I want the methodB
to be called only if the identification is finished.
So if any method is called, it must be able to pause if the identification process is not finished.
The difficulty here is that the methodB
is called from other places and during or after the execution of the login method.
Is this possible with RxJs?
Upvotes: 0
Views: 616
Reputation: 31835
You could expose the authentication information in a BehaviorSubject
:
class AuthenticationService {
private subject = new BehaviorSubject(null);
public info = subject.asObservable();
authenticate() {
this.http.get<AuthInfo>('.../Auth/login').subscribe(x => this.subject.next(x), e => this.subject.error(e))
}
}
Call authenticate
wherever you need in your app (e.g: on a login button)
Then I suggest you to use an interceptor in order to make sure that requests are authenticated before they are sent:
class AuthenticationInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return authenticationService.info.pipe(
tap(x => /* If you need to attach the JWT to an HTTP header, do it there */),
switchMap(() => next.handle(req))
)
}
}
Upvotes: 2
Reputation: 141
You could provide the JWT-Token as an ReplaySubject
within some kind of service (probably your AuthenticationService
, if you have one). Then you could use an HttpInterceptor
to intercept every HttpRequest from your application and add the JWT Token to the Request Headers.
class AuthenticationService {
public token = new ReplaySubject<string>(1)
public login() {
// your login logic here
this.token.next(theToken)
}
}
class AuthInterceptor implements HttpInterceptor {
constructor (private authService: AuthService) {}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return this.authService.token.pipe(
mergeMap(token => {
req = req.clone({
headers: new HttpHeaders({
'Authorization': `bearer ${token}`,
})
});
return next.handle(req);
})
)
}
}
Please note: I haven't tested this code yet and I'm not 100% sure if the ReplaySubject is the right choice here. But using an HttpInterceptor
and a shared service for your token should be the way to go.
You probably also need some additional logic in your AuthInterceptor to not intercept the login request and other requests in your application that don't need the token.
For instructions on how to provide and use interceptors, see the Angular Http Client Guide.
Upvotes: 1