0

我正在尝试创建一个链接,以便在登录(/登录路由)后重定向到 /dashboard/overview 子路由,但没有任何运气。我单击链接,我没有收到任何错误或任何响应。我可以在浏览器的底栏上看到正确的路径,如果我手动输入 url,我会访问正确的页面,路径是/dashboard/overview。我不确定它是否有任何关系的一件事是路由是 AuthGuarded。

我在登录后以编程方式尝试将用户重定向到仪表板,我什至可以在 chrome 控制台上看到“重定向到仪表板”消息

onSignin(form: NgForm){
    const email = form.value.email;
    const password = form.value.password;
    this.user = {email, password};
     this.authServiceSubscription = this.authService.signinUser(this.user).subscribe(
       (response) => {
         //redirect to dashboard
        const loginResultCode = response.login_result_code;
         if (loginResultCode == "SUCCESS") {
                       console.log("Sponsor logged in");
                       this.authService.changeStatusToAuthenticated();
                       //redirect to dashboard
                       console.log('Redirecting to dashboard');
                       this.router.navigate(['/dashboard/overview']);
                   } else {
                       console.log("There were errors with the data");
                       //present errors to the user
                       this.errorMessage = "Los datos de autenticación son incorrectos. Intente nuevamente";
                   }
       },
       (error) => { console.log("Error Login", error); this.errorMessage = "Hubo un error interno, intente de nuevo mas tarde";}
       );
  }

并且还创建了一个routerLink,但它也不起作用,没有任何反应,甚至控制台中没有错误:

  <li><a style="cursor: pointer;" routerLink="/dashboard/overview">Go To Dashboard</a></li>

这是我的路由文件:

const appRoutes: Routes = [
  { path: '', redirectTo: '/', pathMatch:'full'},
  { path: '', component: MainComponent },
  { path: 'signin', component:SigninComponent},
  { path: 'signup', component: SignupComponent},
  { path: 'dashboard', canActivate:[AuthGuard],component: DashboardComponent,
    children: [
      { path: '', redirectTo:'/dashboard/overview', pathMatch: 'full'},
      { path: 'overview', component: OverviewCampaignsComponent },
      { path: 'active', component: ActiveCampaignsComponent},
      { path: 'history', component: HistoryCampaignsComponent}
    ] },
  { path: 'not-found', component: ErrorPageComponent },
  { path: '**', redirectTo: '/not-found' }

]

我什至在仪表板组件的 ngOnInit 上放置了一个 console.log,以查看该组件是否已创建,或者在概述组件中,但我没有任何运气,在以编程方式导航时,我在控制台上看不到任何消息路由器链接。如上所述,当我手动访问时确实收到了消息。有任何想法吗?非常感谢

编辑:显然是我应用到仪表板路由的 authguard 有问题,这是 AuthGuard 文件,可能是它没有发现一些错误,或者返回的值不是应该的值??:

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


@Injectable()
export class AuthGuard implements CanActivate {

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

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
    return this.authService.isAuthenticated().map(isAuth => {
      if (isAuth){
        console.log("Auth Guard approves the access");
        return true;
      }
      else {
        console.log('AuthGuard Denying route, redirecting to signin');
        this.router.navigate(['/signin']);
        return false;
      }
    });
  }
}

authService 上的 isAuthenticated() 方法只返回一个带有用户身份验证状态的 observable。我想知道是否存在竞争条件或其他什么......因为最初通过发出 http 异步请求来设置 observable......如果我将 console.log 放入 isAuthenticated 方法,它会记录在控制台上。如果我将console.log放在authguard函数的地图中,如果它没有被记录,那么由于某种原因代码没有被执行......

auth.service.ts

    import { Injectable, OnInit } from '@angular/core';
    import { Router } from '@angular/router';
    import { Http, Response, RequestOptions, Headers } from '@angular/http';
    import 'rxjs/add/operator/map';
    import {Observable, Subject} from "rxjs/Rx";

    @Injectable()
    export class AuthService implements OnInit {
     userIsAuthenticated = new Subject();
      constructor(private router: Router, private http: Http) {
        this.ngOnInit();
      }

      private getHeaders(){
          let headers = new Headers();
          headers.append('Content-Type', 'application/json');
          headers.append('Accept', 'application/json');
          headers.append('Authorization','Bearer');
          return headers;
      }

      ngOnInit(){

        this.changeStatusToUnauthenticated();
        //initial check with the server
        let options = new RequestOptions({ headers: this.getHeaders(), withCredentials: true });

       this.http.get('http://localhost:3000/api/sponsor/check/login',options)
          .map(response => {
        console.log("Execute this");
            if (response.status === 200) {
              console.log("execute also this");
              this.changeStatusToAuthenticated();
              return Observable.of(true);
            }
          }
        ).catch((err)=>{
          //maybe add in the future if the code is 403 then send him to login otherwise send him elsewhere
          if(err.status === 403){
            console.log('Forbidden 403');
    //        If I want to redirect the user uncomment this line
    //        this.router.navigate(['/signin']);
          }
          this.changeStatusToUnauthenticated();
          return Observable.of(false);
        }).subscribe((isAuth)=>{
           console.log("Initial refresh auth state ", isAuth);
        });

      }

      isAuthenticated(): Observable<boolean> {
  if(this.userIsAuthenticated){
 //if I change this line for return Observable.of(true) it works
   return this.userIsAuthenticated;
 }else{
   return Observable.of(false);
 }
  }

      logout() {
        console.log('logging out');
        let options = new RequestOptions({ headers: this.getHeaders(), withCredentials: true });
        return this.http.get('http://localhost:3000/api/sponsor/logout/', options).map(res=>res.json())
        .subscribe(
            (response) => {
              //redirect to dashboard
             const logoutResultCode = response.code;
              if (logoutResultCode == "200") {
                            console.log("Sponsor logged out successfully");
                            //redirect to dashboard
                            this.changeStatusToUnauthenticated();
                            this.router.navigate(['/signin']);
                        }
            },
            (error) => {
              console.log("Error Logout- Header", error);
              //check for 403 if it's forbidden or a connection error
              this.changeStatusToUnauthenticated();
              this.router.navigate(['/signin']);}
          );

      }

      signinUser(user) {
        console.log("Logging user");
        let options = new RequestOptions({ headers: this.getHeaders(), withCredentials: true });
        return this.http.post('http://localhost:3000/api/sponsor/login/', user, options).map(
          response => response.json());
      }

      registerUser(user) {
        let options = new RequestOptions({ headers: this.getHeaders(), withCredentials: true });
        return this.http.post('http://localhost:3000/api/sponsor/register/', user, options).map(
          response => response.json());
      }

      changeStatusToUnauthenticated(){
        this.userIsAuthenticated.next(false);
      }

      changeStatusToAuthenticated(){
        this.userIsAuthenticated.next(true);
      }


    }

编辑 2:我在 authService 上使用了 Behavior Subject 而不是 Subject 因为它让我得到最后一个发出的值,与您必须订阅的常规主题相比,这是一个非常酷的功能,有时这还不够。下面我的答案的更多细节。

4

1 回答 1

1

最后问题出在 authService 在 isAuthenticated() 方法上返回的内容中,根据日志我显然没有返回已解析的值,因此 authguard 在能够解析到组件的路由之前就卡住了。我通过搜索 rxjs 文档解决了我的问题。我找到了 BehaviorSubject https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/subjects/behaviorsubject.md

它可以让您获得最后一个发出的值,因此我可以返回一个 Observable.of(userIsAuthenticated.getValue()) 并将其传递给 AuthGuard,它现在可以完美运行。我添加了这样的逻辑,如果最后一个发出的值是假的,那么我会做一个虚拟请求来决定是否应该将用户发送到登录屏幕。然后,如果我对服务器发出的每个请求都收到 http 禁止响应,那么这与将 BehaviourSubject 的值更改为 false 是密切相关的。这些东西结合起来将确保前端和后端传统会话之间的一致性,避免后端的过期会话和前端的非过期状态。希望这可以帮助某人。编码:

auth.service.ts

        @Injectable()
        export class AuthService implements OnInit {
         userIsAuthenticated= new BehaviorSubject(null);
          constructor(private router: Router, private http: Http) {
            this.ngOnInit();
          }

          private getHeaders(){
              let headers = new Headers();
              headers.append('Content-Type', 'application/json');
              headers.append('Accept', 'application/json');
              headers.append('Authorization','Bearer');
              return headers;
          }


      ngOnInit() {
        //initial check with the server
        this.doAuthCheck();

      }

      doAuthCheck(): Observable<boolean> {

        let options = new RequestOptions({ headers: this.getHeaders(), withCredentials: true });

        return this.http.get('http://localhost:3000/api/check/login', options)
          .map(response => {
            if (response.status === 200) {
              this.changeStatusToAuthenticated();
              return Observable.of(true);
            }
          }
          ).catch((err) => {
            //maybe add in the future if the code is 403 then send him to login otherwise send him elsewhere
            if (err.status === 403) {
              console.log('Forbidden 403');
              //        If I want to redirect the user uncomment this line
              //        this.router.navigate(['/signin']);
            }
            this.changeStatusToUnauthenticated();
            return Observable.of(false);
          });
      }

      isAuthenticated(): Observable<boolean> {
        const isAuth = this.userIsAuthenticated.getValue();
        if (isAuth) {
          return Observable.of(isAuth);
        } else {
          return this.doAuthCheck();
        }
      }


  logout() {
    console.log('logging out');
    let options = new RequestOptions({ headers: this.getHeaders(), withCredentials: true });
    return this.http.get('http://localhost:3000/api/logout/', options).map(res => res.json())
      .subscribe(
      (response) => {
        //redirect to dashboard
        const logoutResultCode = response.code;
        if (logoutResultCode == "200") {
          console.log("logged out successfully");
          //redirect to dashboard
          this.changeStatusToUnauthenticated();
          this.router.navigate(['/signin']);
        }
      },
      (error) => {
        console.log("Error Logout- Header", error);
        //check for 403 if it's forbidden or a connection error
        this.changeStatusToUnauthenticated();
        this.router.navigate(['/signin']);
      }
      );

  }



  signinUser(user) {
    console.log("Logging user");
    let options = new RequestOptions({ headers: this.getHeaders(), withCredentials: true });
    return this.http.post('http://localhost:3000/api/login/', user, options).map(
      response => response.json());
  }

  registerUser(user) {
    let options = new RequestOptions({ headers: this.getHeaders(), withCredentials: true });
    return this.http.post('http://localhost:3000/api/register/', user, options).map(
      response => response.json());
  }

changeStatusToUnauthenticated() {
    this.userIsAuthenticated.next(false);
  }

  changeStatusToAuthenticated() {
    this.userIsAuthenticated.next(true);
  }

        }

auth-guard.service.ts

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


@Injectable()
export class AuthGuard implements CanActivate {

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

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
    return this.authService.isAuthenticated().map(isAuth => {
      console.log("is Authenticated",isAuth);
      if (isAuth){
        console.log("Auth Guard approves the access");
        return true;
      }
      else {
        console.log('AuthGuard Denying route, redirecting to signin');
        this.router.navigate(['/signin']);
        return false;
      }
    });
  }
}

路线文件

const appRoutes: Routes = [
  { path: '', redirectTo: '/', pathMatch:'full'},
  { path: '', component: MainComponent },
  { path: 'signin', component:SigninComponent},
  { path: 'signup', component: SignupComponent},
  { path: 'dashboard', canActivate:[AuthGuard],component: DashboardComponent,
    children: [
      { path: '', redirectTo:'/dashboard/overview', pathMatch: 'full'},
      { path: 'overview', component: OverviewCampaignsComponent },
      { path: 'active', component: ActiveCampaignsComponent},
      { path: 'history', component: HistoryCampaignsComponent}
    ] },
  { path: 'not-found', component: ErrorPageComponent },
  { path: '**', redirectTo: '/not-found' }

]
于 2017-06-15T20:43:38.013 回答