I have an auth service with a login method and a login component.
From my login components' onSubmit method I call the services' login method and subscribe to the answer.
The challenging part is, that in that login method I have to do multiple succeeding requests (one call to get the generated token for a user name, then use that token to encrypt an entered password and make another call to then really login on the server). Not sure how to do this, tried many approaches, but I'm still quite new to angular and wonky when it comes to Observable.
login component:
this.authenticationService.login(this.f.username.value, this.f.password.value)
.pipe(first())
.subscribe(
data => {
this.router.navigate([this.returnUrl]);
},
error => {
this.alertService.error(error);
this.loading = false;
});
auth service:
login(username, password) {
return this.http.post<any>(`${config.apiUrl}/users/authenticate`, { username, password })
.pipe(map(user => {
// store user details and jwt token in local storage to keep user logged in between page refreshes
localStorage.setItem('currentUser', JSON.stringify(user));
this.currentUserSubject.next(user);
return user;
}));
}
I tried multiple nested calls using http.get().pipe and lots of variants of that, but obviously I'm still missing some basic understanding.
The snippet/idea is from here: https://jasonwatmore.com/post/2019/06/10/angular-8-user-registration-and-login-example-tutorial
Edit:
I got a solution, but it's ugly, some improvements possible ?
return new Observable((observer) => {
this.http.get<any>(urlToken)
.pipe(map(answer => {
if (answer['type'] != 'Success') { return; }
let token = answer['message'];
urlLogin += '&passphrase=' + someSalt(username, password, token);
return this.http.get<any>(urlLogin)
.pipe(map(answer2 => {
if (answer2['type'] != 'Success') { return; }
let sessionId = answer2['message'];
let user = new User();
user.username = username;
user.sessionId = sessionId;
localStorage.setItem('currentUser', JSON.stringify(user));
this.currentUserSubject.next(user);
observer.next(user);
})).subscribe();
})).subscribe();
});
when chaining observables in a sequential manner a concept called higher-order-mapping is used (i suggest this article). one of these higher-order-mapping operators is concatMap and combining it with tap operator will help you achive your goals in the correct way. your solution is not just ugly :( it is not testable and unnecessarily complicated. your
loginmethod should be like this;here is a demonstration of above concepts https://stackblitz.com/edit/angular-qvhay8