Angular 2 路由器 - CanActivate 守卫

3
我正在实现CanActivate守卫,如果用户的会话无效,则将其重定向到登录页面。
检查会话是否有效是通过服务完成的,因此从守卫中我订阅服务调用以获取会话有效状态。
我已经调试了代码,似乎一切都正常工作,事实上,当会话无效时,应用程序确实会重定向回登录页面。但是当我从守卫返回true时,页面不会加载。
我的代码类似于Angular文档( Angular文档)( Plunker上的代码)中列出的内容。
我不确定我是否在守卫本身中实现了错误。我能看到的区别是守卫正在访问服务中的属性- 但我认为那不应该很重要。据我所知,从守卫返回true将简单地继续正常的路由操作。
注意:我正在使用Angular RC3
代码:

守卫

export class MyGuard implements CanActivate {
    constructor(private checkSessionService: CheckSessionService, private router: Router) {}

    canActivate(
    next:  ActivatedRouteSnapshot,
    state: RouterStateSnapshot
    ) {
        this.checkSessionService.checkUserSession(localStorage.getItem('userToken'))
        .subscribe(validSessionReturn => {

            if (validSessionReturn) {
                return true;
            } else {
                // redirect to login
                this.router.navigateByUrl('/login');
                return false;
            }
        },
        error => console.log(error));
    }
}

编辑

我进行了进一步的调查,发现我遇到的问题与我试图从subscribe方法本身返回布尔值有关。作为测试,我尝试了以下内容,一切都按预期工作:

export class MyGuard implements CanActivate {
    constructor(private checkSessionService: CheckSessionService, private router: Router) {}

    canActivate(
    next:  ActivatedRouteSnapshot,
    state: RouterStateSnapshot
    ) {
        if(localStorage.getItem('userToken') !== null) {
            return true; // or return Observable.of(true);
        } else {
            return false; // or return Observable.of(false);
        }
    }
}

你可以从上面的代码中注意到,可以返回booleanObservable<boolean>。我实现的CheckSessionService确实返回Observable<boolean>。事实上,当我尝试下面的代码时,一切都按预期工作,这意味着如果会话有效,则页面成功加载,否则路由被停止:
export class MyGuard implements CanActivate {
    constructor(private checkSessionService: CheckSessionService, private router: Router) {}

    canActivate(
    next:  ActivatedRouteSnapshot,
    state: RouterStateSnapshot
    ) {
        return this.checkSessionService.checkUserSession(localStorage.getItem('userToken'));
    }
}

然而,通过以上示例,我无法找到一种基于服务检索的值来重定向到特定页面的方法。我的问题现在是是否有一种方法可以在没有订阅方法的情况下检查this.checkSessionService.checkUserSession(localStorage.getItem('userToken'))的结果,或者是否有不同的方法可以从subscribe方法中返回。我尝试过:
if(this.checkSessionService.checkUserSession(localStorage.getItem('userToken')) === Observable.of(false))

但是如预期的那样,它没有起作用。

1个回答

2

替换

this.checkSessionService...

by

return this.checkSessionService...

不要只订阅可观测对象并返回订阅,还必须返回可观测对象本身,但在其为假时插入某些内容:

return this.checkSessionService.checkUserSession(localStorage.getItem('userToken'))
    .do(‌​function(authenticated) { 
        if (!authenticated) ... 
    });

我之前尝试过这个。然而,如果使用我现有的代码进行操作,会返回一个“Subscription”而不是允许的“boolean”或“Observable<boolean>”。我确定我现有的代码没问题,只是当返回“true”时,它表现得好像我返回了“false”,然后停止了路由操作。 - Daniel Grima
您的回复似乎指引我朝着正确的方向,但我有一个小问题,我已经在问题中更新了我的发现。 - Daniel Grima
1
是的,我回答得有点太快了,把 Promises 和 Observables 搞混了。基本上,你需要返回一个 Observable<boolean>,这就是你的服务返回的内容,但如果 boolean 是 false,你还必须做一些事情。这就是 do 运算符所允许的操作。http://reactivex.io/documentation/operators/do.html。`return this.checkSessionService.checkUserSession(localStorage.getItem('userToken')).do(function(authenticated) { if (!authenticated) ... });` - JB Nizet
太好了!我刚刚更新了代码,一切正常!我确实需要更多地了解Observables :) 到目前为止,我只使用了subscribe函数,并认为它在这种情况下也应该工作,但我错了。非常感谢您的帮助。 :) - Daniel Grima
1
我也和他们一样受苦 :) - JB Nizet
只需要一点时间来习惯就好了 :) 顺便说一下,我会接受这个答案的,只是请在答案中更新一下代码。这可能会帮助将来的其他人 :) - Daniel Grima

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接