9

我正在构建一个应用程序,未经身份验证的用户根本无法访问。

我写了一个LoggedInGuard,但现在我必须添加canActivate: [LoggedInGuard]到我的路由器配置中的每个LoginComponent路由(除了)。

有没有更好的方法让这个工作?


我的文件/模块布局如下所示:

app/
  AppModule
  AppRoutingModule
  AppComponent

  authentication/
    AuthenticationModule
    AuthenticationRoutingModule
    LoginComponent

  contacts/
    ContactsModule
    ContactsRoutingModule
    ContactListComponent

  users/
    UsersModule
    UsersRoutingModule
    UserEditComponent

  ...

也许可以创建两个单独的路由空间(一个用于登录,一个用于应用程序的其余部分)并将保护仅应用于应用程序部分的其余部分?


我希望有一个简单的解决方案。

提前致谢!

4

2 回答 2

9

我认为我以一种更合乎逻辑的方式来做这件事。我想这是一种意见。secured pages我用和分隔我的应用程序public pages。我为每组使用模板。所以public component,然后secure componentguardsecure template

确保您添加[Guard]到需要保护的完整路线。

因此,当我确保一条路线时,我会将父母添加到app.routing.ts

const APP_ROUTES: Routes = [
    { path: '', redirectTo: '/home', pathMatch: 'full', },
    { path: '', component: PublicComponent, data: { title: 'Public Views' }, children: PUBLIC_ROUTES },
    { path: '', component: SecureComponent, canActivate: [Guard], data: { title: 'Secure Views' }, children: SECURE_ROUTES }
];



export const routing = RouterModule.forRoot(APP_ROUTES);

确保注意到这条线,

 { path: '', component: SecureComponent, canActivate: [Guard], data: { title: 'Secure Views' }, children: SECURE_ROUTES }

所以我创建了 2 个布局

/public/ 所有公共组件

/public/public.routes.ts

/secure/ 所有安全组件

/secure/secure.routes.ts

安全路线

请注意,这些路由现在不需要Guard,因为它由模板父级处理。

export const SECURE_ROUTES: Routes = [
    { path: '', redirectTo: 'overview', pathMatch: 'full' },
    { path: 'items', component: ItemsComponent },
    { path: 'overview', component: OverviewComponent },
    { path: 'profile', component: ProfileComponent },
];

app.routing.ts 中的主要路由

const APP_ROUTES: Routes = [
    { path: '', redirectTo: '/home', pathMatch: 'full', },
    { path: '', component: PublicComponent, data: { title: 'Public Views' }, children: PUBLIC_ROUTES },
    { path: '', component: SecureComponent, canActivate: [Guard], data: { title: 'Secure Views' }, children: SECURE_ROUTES }
];

export const routing = RouterModule.forRoot(APP_ROUTES);

在目录 /layouts 我创建了一个布局

/layouts/secure.component.ts

/layouts/secure.component.html

/layouts/public.component.ts

/layouts/public.component.html

一切都通过布局布线,或者public是安全的。secure[Guard]

然后我使用本地存储中的令牌处理身份验证。

@Injectable()
export class Guard implements CanActivate {

    constructor(protected router: Router, protected auth: Auth ) {}

     canActivate() {
        if (localStorage.getItem('access_token')) {
            // logged in so return true
            return true;
        }
        // not logged in so redirect to login page
        this.router.navigate(['/home']);
        return false;
    }
}

一旦我像这样设置我的应用程序,我就会将所有需要安全的路由放在安全目录中,并将公共路由放在公共位置。然后我在他们各自目录中的 public.routes.ts 文件或 secure.routes.ts 文件中创建他们的路由。

于 2016-12-19T09:35:33.910 回答
5

通过将守卫移动到路由器事件侦听器中,我能够提供一组跨越多个模块的全局守卫。

为了让所有请求都触发事件监听器,我将它插入到 AppComponent 中。

请注意,在下面的两个示例中,您仍然可以为各个路线添加自定义守卫,并且这些守卫仍然有效。

没有警卫

您可以删除对守卫的使用,而是直接在事件侦听器中实现逻辑。

import { Component, OnInit } from '@angular/core';
import { Router, RoutesRecognized } from '@angular/router';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/filter';

// I use a service to keep track of the authentication ticket.
// Replace this with whatever mechanism you use.
import { AuthenticationService }  from './_services/index';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  constructor(
      private router: Router,
      private authService: AuthenticationService
  ) {}

  ngOnInit() {
    this.router.events
    .filter(event => event instanceof RoutesRecognized)
    .subscribe((event: RoutesRecognized) => {
      const url = event.urlAfterRedirects;

      // Public URLs don't need any kind of authorization.
      if (url === '/public' || url.startsWith('/public/') || url.startsWith('/public?')) {
        return;
      }

      // Everything else must be authenticated.
      if (!this.authService.isAuthenticated()) {
        // Allow for the login page to redirect back to the originally
        // requested page.
        this.router.navigate(['/public/login'], { queryParams: { returnUrl: state.url } });
      }
    });
  }
}

传递到任何子页面的/public请求无论如何都会通过,但任何其他请求都必须经过身份验证,否则它将重定向到/public/login.

注意重定向页面不在保护区内,否则路由器将进入无限循环。

带卫兵

下面的实现展示了我如何重用现有的守卫。仅当您需要保留它们,或者它使您的代码更清晰时才这样做。

import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRoute, RoutesRecognized, CanActivate } from '@angular/router';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/filter';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/mergeMap';

// Reused guards.
import { AdminGuard, AuthGuard } from './_guards/index';


@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {

  constructor(
      private route: ActivatedRoute,
      private router: Router,
      private adminGuard: AdminGuard,
      private authGuard: AuthGuard
  ) {}

  ngOnInit() {
    this.router.events
    .filter(event => event instanceof RoutesRecognized)
    .subscribe((event: RoutesRecognized) => {
      // Public pages don't require authentication.
      if (this.isSubPage(event, '/public')) {
        return;
      }

      // All other requests MUST be done through an
      // authenticated connection.  The guard performs
      // the redirection for us.
      if (!this.callCanActivate(event, this.authGuard)) {
        return;
      }

      // Administration pages require additional restrictions.
      // The guard performs the redirection for us.
      if (this.isSubPage(event, '/admin')) {
        if (!this.callCanActivate(event, this.adminGuard)) {
          return;
        }
      }
    });
  }

  callCanActivate(event: RoutesRecognized, guard: CanActivate) {
    return guard.canActivate(this.route.snapshot, event.state);
  }

  isSubPage(event: RoutesRecognized, parent: string) {
    const url = event.urlAfterRedirects;
    return (url === parent
        || url.startsWith(parent + '/')
        || url.startsWith(parent + '?'));
  }
}

此示例与上面的示例相同,但增加了对该/admin区域的保护,以确保用户也具有管理权限。

于 2017-03-31T18:01:30.833 回答