First off sorry for the title, I had no idea what to call this.
I am working on a project that requires an authentication guard which I originally had working great. Bascially all it did was check to see if there was a valid token in local storage. Pretty simple.
Well as most Apps do, it got a little more complicated in the form of needing to set a "Reset Password" flag on the users profile which would force them to reset their password on the next login. That's where the guard stopped working as expected. I think that the return Observable.of(true)
isn't quite making up the chain, because when the guard runs the console logs PASSWORD RESET, PROCEED
, but fails to allow the user to continue. I am not well versed enough with RxJs to know what needs to be done. Also I apologize in advance for the observable pyramid of doom. Refactoring that is something on the "would be nice to do" list.
@Injectable()
export class AuthenticationGuard implements CanActivate {
constructor(
private _Router: Router,
private _LocalUserService: LocalUserService,
private _SystemSettingsService: SystemSettingsService,
private _UsersService: UsersService
) { }
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> {
return this._SystemSettingsService.getSystemSetting('AUTHENTICATION')
.map(_SystemSetting => {
// Check for Authentication to be Enabled
if (_SystemSetting.data.settingValue.enabled) {
// Check for an Authentication Token Locally
this._LocalUserService.getLocalUserObject()
.subscribe(_LocalUserObject => {
// Check if Local User Object is Empty and if a Token is Present
if (_LocalUserObject && _LocalUserObject.token) {
// Retrieve the user that the token is associated to from API
this._UsersService.getUser(_LocalUserObject.userID)
.subscribe(_User => {
// If password reset is enabled, force user to reset their password.
if (_User.data.userPasswordReset) {
this._Router.navigate(['/gateway/password-reset']);
return Observable.of(false);
// If password reset is false, allow the user to proceed.
} else {
console.log('PASSWORD RESET, PROCEED');
return Observable.of(true);
}
})
// If Local User Object is invalid, navigate to Login Page.
} else {
// not logged in so redirect to login page with the return url
this._Router.navigate(['/gateway/login'], { queryParams: { returnUrl: state.url } });
return Observable.of(false);
}
})
// If Athentication is disabled allow the user to bypass authentication
} else {
return Observable.of(true);
}
})
}
}
Any suggestions would be much appreciated... Thanks
I ended up figuring it out. I started by consolidating most of the observables into a single call. I still have one nested observable. But I also found out that you have to mindful of your return type. Within the switchMap I am returning Observables, however within the nested map operation it switches to boolean.
@Injectable()
export class AuthenticationGuard implements OnInit, CanActivate {
systemSetting$: Observable<any> = this._SystemSettingsService.getSystemSetting('AUTHENTICATION');
localUserObject$: Observable<LocalUserObject> = this._LocalUserService.getLocalUserObject();
initialData = Observable.zip(
this.systemSetting$,
this.localUserObject$
);
constructor(
private _Router: Router,
private _LocalUserService: LocalUserService,
private _SystemSettingsService: SystemSettingsService,
private _UsersService: UsersService
) { }
ngOnInit() {
}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
return this.initialData.switchMap(_Result => {
// Check for Authentication to be Enabled
if (_Result[0].data.settingValue.enabled) {
// Check if Local User Object is Empty and if a Token is Present
if (_Result[1] && _Result[1].token) {
return this._UsersService.getUser(_Result[1].userID)
.map(_User => {
// If password reset is enabled, force user to reset their password.
if (_User.data.userPasswordReset) {
this._Router.navigate(['/gateway/password-reset']);
return false;
// If password reset is false, allow the user to proceed.
} else {
console.log('PASSWORD RESET, PROCEED');
return true;
}
})
// If Local User Object is invalid, navigate to Login Page.
} else {
// not logged in so redirect to login page with the return url
this._Router.navigate(['/gateway/login'], { queryParams: { returnUrl: state.url } });
return Observable.of(false);
}
// If Authentication is disabled allow the user to bypass authentication
} else {
return Observable.of(true);
}
})
}
}