Angular2:Global Guard(用户必须始终登录)

时间:2016-12-19 09:29:13

标签: angular angular2-routing angular2-guards

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

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

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

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

app/
  AppModule
  AppRoutingModule
  AppComponent

  authentication/
    AuthenticationModule
    AuthenticationRoutingModule
    LoginComponent

  contacts/
    ContactsModule
    ContactsRoutingModule
    ContactListComponent

  users/
    UsersModule
    UsersRoutingModule
    UserEditComponent

  ...

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

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

提前致谢!

2 个答案:

答案 0 :(得分:7)

我想我是以更合乎逻辑的方式做到的。我想这是一个意见。我按secured pagespublic pages分隔了我的申请。我为每一组使用模板。因此,public componentsecure component会将guard放在secure 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

所有内容都通过布局publicsecure进行路由,[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文件中创建它们各自的目录中的路由。

答案 1 :(得分:4)

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

要为所有请求触发事件侦听器,我将其插入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区域添加了保护,这可确保用户也具有管理权限。