【问题标题】:Angular 4 canActivate with nested observables not workingAngular 4 canActivate 嵌套的可观察对象不起作用
【发布时间】:2017-07-13 21:00:40
【问题描述】:

首先对不起标题,我不知道该怎么称呼它。

我正在从事一个需要身份验证保护的项目,我最初的工作很好。基本上,它所做的只是检查本地存储中是否有有效的令牌。很简单。

正如大多数应用程序所做的那样,它需要在用户个人资料上设置“重置密码”标志,这将迫使他们在下次登录时重置密码。这就是警卫按预期停止工作的地方。我认为return Observable.of(true) 并没有完全构成链条,因为当守卫运行控制台日志PASSWORD RESET, PROCEED 时,但无法让用户继续。我对 RxJs 不够精通,不知道需要做什么。我也为可观察到的末日金字塔提前道歉。重构是“最好做”列表中的事情。

@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);
            }
        })
    }
}

任何建议将不胜感激......谢谢

【问题讨论】:

    标签: angular rxjs observable angular2-services


    【解决方案1】:

    我最终弄明白了。我首先将大部分 observables 合并到一个调用中。我仍然有一个嵌套的 observable。但我也发现你必须注意你的返回类型。在 switchMap 中,我返回 Observables,但在嵌套映射操作中,它切换为布尔值。

    @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);
    			}
    		})
    	}
    }

    【讨论】:

    • 我建议使用flatMap(不幸的是也被称为mergeMap)来减少嵌套。您还可以将多个ifs 替换为filter,以进一步减少嵌套。
    猜你喜欢
    • 1970-01-01
    • 2021-03-01
    • 2018-04-13
    • 2022-11-25
    • 2020-08-28
    • 2018-02-03
    • 1970-01-01
    • 1970-01-01
    • 2012-06-13
    相关资源
    最近更新 更多