2017-08-25 87 views
1

观察值我遵循了很多教程,并尝试了许多组合,但无法使这项工作。Angular 4:无法订阅从CanActivate AccessGuard

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

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

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('用户'),但不能使用observable。

任何帮助表示赞赏。

谢谢!

+0

从你的解释,弹出必须是不是后卫,但在网页组件,在其内部可以实现'ngOnInit()'检查,如果用户'isSignedIn',如果不是,用登录表单触发弹出窗口。 Guard在返回false之前只能重定向到主页。 – Vadim

回答

0

这是正确答案,问题出在订阅方法里面的逻辑里。

这里是正确的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; 
     } 
    } 
} 
+0

@Robin Dijkhof逻辑在canActivate方法中是允许的。通过这种方式,您可以对每个经过验证的路线使用相同的过程。 – SBO

+0

允许逻辑,但显示模型不仅仅是逻辑。你也确定这是工作。订阅是异步的,所以这看起来很奇怪。我怀疑它永远不会是假的。如果它有效,你是幸运的,但如果有一个小的延迟会发生什么。 –

+0

嗯..它甚至可以在生产服务器上运行。你的意思是我应该返回this.authService.isLoggedIn.subscribe()结果,而不是在最后返回true吗? – SBO

0

你需要返回一个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); 
} 
+0

我怎样才能显示弹出窗口,并把登录内每个私人页面? – SBO

+0

我不认为这是可能的从后卫。我认为将重定向到专用的登录页面并发送请求将会更好。成功登录后,您可以重新导向。 –

+0

我想做这样的事情:https://stackoverflow.com/questions/39935721/how-to-return-observable-from-subscribe – SBO