首页 专题 H5案例 前端导航 UI框架

Angular4 开发实战:(12) 安全路由

作者:TG 日期: 2017-06-27 字数: 10208 阅读: 8330
对于一些管理系统,我们总是需要一些权限控制,就好像总是需要登录才能访问到个人中心之类的页面。

Angular给我们提供了很强大的安全守卫。

CanActivate

使用Angular CLI,我们可以创建一个基础安全守卫:

ng g guard auth

基础模板如下:

// app/guard/auth.guard.ts   


import { Injectable } from '@angular/core';  

import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';  

import { Observable } from 'rxjs/Observable'; 


@Injectable() 

export class AuthGuard implements CanActivate {   

    canActivate(   

      next: ActivatedRouteSnapshot,   

      state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {   

        return true;   

    }  

}

canActivate()返回true,表示可以进入指定路由;否则停留到当前页面。
canActivate()可以接受两个可选的参数:
  • ActivateRouteSnapshot:将被激活的路由
  • RouterStateSnapshot:未来的路由状态
如何使用呢?

很简单:

// app/modules/app-routing.module.ts  

import {AuthGuard} from '../guard/auth.guard';   


const routes: Routes = [      

  { path: 'images',   

    canActivate: [AuthGuard],   

    component: DemoImageComponent}  

];   


@NgModule({      

  providers: [AuthGuard]  

})  

export class AppRoutingModule {  }

在上面的代码中,我们给路由images添加了一个安全守卫canActivate: [AuthGuard]
注意:要将安全守卫AuthGuard注册到模块的提供商providers中。

当然,我们肯定需要一些验证,在这里,我们使用`localStorage`来设置用户是否登录。

修改一下代码:

// app/guard/auth.guard.ts   


canActivate(   

  next: ActivatedRouteSnapshot,   

  state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {   

    if (localStorage.getItem('user')) {   

      return true;   

    } else {   

      return false;   

    }   

}

新增页面:

// app/demo/demo-guard.component.html   


<p>账号是123,密码也是123</p>   

<p>   

  <input type="text" #account>   

  <input type="password" #pwd>   

  <button (click)="onSubmit(account.value, pwd.value)">登录</button>   

</p>    


<a routerLink="/images">这是个照片链接,你懂得。</a>     


// app/demo/demo-guard.component.ts   


onSubmit(account: string, pwd: string) {   

  if (account === '123' && pwd === '123') {   

    localStorage.setItem('user', JSON.stringify({account: account, password: pwd}));   

    alert('登录成功,你可以看图片了,嘿嘿');   

  }   

}

在上面的代码中,提供了账号和密码的输入框,只有输入正确的账号和密码,才可以提交登录,然后设置一个localStorage,也就是user。

而在成功提交之前,你点击链接会发现并没有什么反应。

这就是简单的安全路由,只有满足一定条件时,才允许跳转。

上面只是一个很简单的例子,你还可以给安全守卫添加更多的逻辑,比如当不通过时跳转到登录页面等。

注:你会发现我们给路由传递的是一个数组`canActivate: [AuthGuard]`,这表示安全路由检测可以多个,并且只有当所有都返回true时,才通过;也就是说,只要有一个返回false,则不通。

CanActivateChild

CanActivate只是保护当前路由,而不会检测其子路由(如果有的话)。 要给其所有子路由添加安全守卫,我们可以使用CanActivateChild

CanActivateChild的使用方法和CanActivate类似,两者的区别在于前者会在其任意一个子路由变化的时候检测。

import { Injectable } from '@angular/core';  

import {   

  CanActivate, Router, ActivatedRouteSnapshot, RouterStateSnapshot, CanActivateChild

} from '@angular/router';   


@Injectable()  

export class AuthGuard implements CanActivate, CanActivateChild {   

  /* . . . */   

  canActivateChild(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {   

    return this.canActivate();   

  }   

}

使用方式也和CanActivate一样要添加到提供商中(provider),然后使用:

// src/app/app.module.ts   


const routes: Routes = [   

  {   

    path: 'demoGuard',   

    component: DemoGuardComponent,   

    children: [   

     {   

        path: '',   

        canActivateChild: [AuthChildGuard],   

        children: [   

          {path: 'child', component: DemoGuardChildComponent}   

        ]   

     }   

    ]   

  }  

];   


@NgModule({   

  imports: [...],   

  exports: [...],   

  providers: [AuthGuard, AuthChildGuard]  

})  

export class AppRoutingModule { }

CanDeactivate

有些情况(比如个人信息修改页面),我们需要监听用户是否修改了某些信息,然后当用户离开时,我们需要做一些提示,这时我们就需要监听到用户啥时离开了。

在Angular中,我们使用CanDeactivate守卫。 创建一个守卫:

// src/app/guard/canDeactivateGuard.ts   


import {ActivatedRouteSnapshot, CanDeactivate, RouterStateSnapshot} from '@angular/router';  

import {Injectable} from '@angular/core';  

import {DemoGuardComponent} from '../demo/demo-guard/demo-guard.component';   


@Injectable()  

export class CanDeactivateGuard implements CanDeactivate<DemoGuardComponent> {    

  oldName: string = '123';   

  canDeactivate(component: DemoGuardComponent,   

    route: ActivatedRouteSnapshot,   

   state: RouterStateSnapshot): Promise<boolean> | boolean {   

    if (this.oldName === component.name) {   

      return true;   

    }   

    return confirm('信息未保存,确认要离开!');   

  }  

}

在上面的代码中,oldName是假设原值,用来和DemoGuardComponent组件(这也是当前页面的组件)中的name值进行比较,如果相等,表示值未修改,可直接跳转;如修改了,则弹出提示框。 接着再增加以下代码:

// src/app/demo/demo-guard.component.html   


<div class="box">   

  <h4> CanDeactivateGuard</h4>   

  <p>   

    <input type="text" [(ngModel)]="name"> (尝试修改表单的内容,然后点击其他页面)   

  </p>  

</div>   


// src/app/demo/demo-guard.component.ts  

export class DemoGuardComponent implements OnInit {    

  name: string = '123';   

}

在上面,我们使用NgModel来双向绑定到属性name上,也就是安全守卫CanDeactivateGuard中要比较的值。

如有疑问或更好建议,欢迎在下方评论区留言!


目录