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

Ben*_*n M 9 angular2-routing angular2-guards angular

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

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

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


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

app/
  AppModule
  AppRoutingModule
  AppComponent

  authentication/
    AuthenticationModule
    AuthenticationRoutingModule
    LoginComponent

  contacts/
    ContactsModule
    ContactsRoutingModule
    ContactListComponent

  users/
    UsersModule
    UsersRoutingModule
    UserEditComponent

  ...
Run Code Online (Sandbox Code Playgroud)

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


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

提前致谢!

wun*_*uno 7

我想我是以更合乎逻辑的方式做到的.我想这是一个意见.我用secured pages和分开我的申请public pages.我为每一组使用模板.所以public component,secure 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);
Run Code Online (Sandbox Code Playgroud)

确保注意到这一行,

 { path: '', component: SecureComponent, canActivate: [Guard], data: { title: 'Secure Views' }, children: SECURE_ROUTES }
Run Code Online (Sandbox Code Playgroud)

所以我创建了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 },
];
Run Code Online (Sandbox Code Playgroud)

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);
Run Code Online (Sandbox Code Playgroud)

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

/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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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


小智 6

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

为了使事件侦听器触发所有请求,我将其插入到 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 } });
      }
    });
  }
}
Run Code Online (Sandbox Code Playgroud)

传递到 的任何子页面的请求都/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 + '?'));
  }
}
Run Code Online (Sandbox Code Playgroud)

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