【问题标题】:Angular 4: cannot subscribe observable value from CanActivate AccessGuardAngular 4:无法从 CanActivate AccessGuard 订阅可观察值
【发布时间】:2018-02-03 21:26:58
【问题描述】:

我遵循了很多教程并尝试了很多组合,但无法完成这项工作。

当用户登录时,我需要让路由可用。如果他不是,我需要将他重定向到主页(this._popupService.setCallbackRoute(route.url.join('/'))) 并显示一个弹出窗口(this._popupService.showPopUp()),让他登录或注册。

我无法从 authService 获取同步值。这是我的代码:

app.module.ts

imports: [
    BrowserModule,
    FormsModule,
    HttpModule,
    RouterModule.forRoot(
        {path: '', component: HomepageComponent},
        {
            path: 'protectedRoute',
            component: SubmitComponent,
            data: {requiresLogin: true},
            canActivate: [AccessGuard]
        }
    ),
    ...
]

auth.service.ts

 @Injectable()
export class AuthService {

    private loggedIn: Subject<boolean> = new Subject<boolean>();

    get isLoggedIn() {
        return this.loggedIn.asObservable();
    }

    login(user: IUser) {
        return this._http.get('assets/api/responseSuccess.json?email=' + user.email + '&password=' + user.password)
            .map((responseLogin => {
                const jsonResponse = responseLogin.json();
                if (jsonResponse.response === 'success') {
                    const userResponse: IUser = jsonResponse.user;
                    this._sessionService.setUserSession(userResponse);
                    this.loggedIn.next(true);
                    return true;
                } else {
                    this._customFlashMessages.show('Got error login, please check your credentials and try again!');
                    return false;
                }
            }));
    }
}

accessGuard.service.ts

import {Injectable} from '@angular/core';
import {ActivatedRouteSnapshot, CanActivate, Router} from '@angular/router';
import {Observable} from 'rxjs/Observable';
import {AuthService} from './auth.service';
import {PopUpService} from './popup.service';

@Injectable()
export class AccessGuard implements CanActivate {
    loggedIn$: Observable<boolean>;

    constructor(private authService: AuthService, private _popupService: PopUpService, private router: Router) {
        this.loggedIn$ = this.authService.isLoggedIn;
    }

    canActivate(route: ActivatedRouteSnapshot): Observable<boolean> | Promise<boolean> | boolean {
        const requiresLogin = route.data.requiresLogin || false;
        if (requiresLogin) {
            this.authService.isLoggedIn.subscribe( // even tried with .map()
                result => {
                    console.log(result); // Logs a promise object
                    if (!result) {
                        console.log("protected route"); // Never reached
                        // If not logged in shop popup and stay on that page
                        this._popupService.showPopUp();
                        this._popupService.setCallbackRoute(route.url.join('/'));
                        return false;
                    }
                    console.log('logged in'); // Never reached
                    return true;
                });
        }
        return true;
    }
}

我尝试了几件事。如果我直接检查 sessionStorage('user') 但不能使用 observable,我的代码就可以工作。

感谢任何帮助。

谢谢!

【问题讨论】:

  • 根据您的解释,弹出窗口必须不在保护范围内,而是在主页组件中,其中可以实现ngOnInit() 检查用户是否isSignedIn,如果不是,则使用登录名触发弹出窗口形式。 Guard 只需重定向到主页,然后返回false

标签: javascript angular typescript


【解决方案1】:

这是正确答案,问题出在订阅方法内部的逻辑上。

这是正确的 accesGuard.service.ts

@Injectable()
export class AccessGuard implements CanActivate {

    constructor(private authService: AuthService, private _popupService: PopUpService, private router: Router) {
    }

    canActivate(route: ActivatedRouteSnapshot): Observable<boolean> | Promise<boolean> | boolean {
        const requiresLogin = route.data.requiresLogin || false;
        if (requiresLogin) {
            this.authService.isLoggedIn.subscribe(
                result => {
                    if (!result) {
                        // If not logged in shop popup and stay on that page
                        this._popupService.showPopUp();
                        this._popupService.setCallbackRoute(route.url.join('/'));
                        this.router.navigate(['/']);
                        return false;
                    }
                    return true;
                });

            return true;
        }else{

        return true;
       }
    }
}

【讨论】:

  • @Robin Dijkhof 逻辑在 canActivate 方法中是允许的。通过这种方式,您可以对每个经过身份验证的路由使用相同的过程。
  • 允许使用逻辑,但显示模型不仅仅是逻辑。你也确定这是有效的。订阅是异步的,所以这看起来很奇怪。我怀疑它永远不会是假的。如果它有效,你很幸运,但如果有一点延迟会发生什么。
  • 嗯.. 它甚至可以在生产服务器中使用。你的意思是我应该返回 this.authService.isLoggedIn.subscribe() 结果而不是最后返回 true 吗?
  • 看看这个问题,明白我的意思:stackoverflow.com/questions/45847183/…
  • 是的,我明白了。我用 else 语句更新了我的代码。这应该适用于任何情况。
【解决方案2】:

你需要返回一个 observable。

canActivate(route: ActivatedRouteSnapshot): Observable<boolean> | Promise<boolean> | boolean {
    const requiresLogin = route.data.requiresLogin || false;
    if (requiresLogin) {
        return this.authService.isLoggedIn;
    }
    return Observable.of(false);
}

【讨论】:

  • 我怎样才能显示弹出窗口并将登录名放在每个私人页面中?
  • 我认为守卫不可能做到这一点。我认为最好重定向到一个专用的登录页面并用它发送请求。成功登录后,您可以重定向回来。
  • 我想做这样的事情:stackoverflow.com/questions/39935721/…
  • 见我上面的评论。谢谢你的回答。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-06-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-15
  • 2018-08-08
  • 2019-11-12
相关资源
最近更新 更多