Angular2使用Guard和Resolve进行验证和权限控制

我们在开发web应用时,在服务器端都会控制某种或某个用户是否有权限调用某个接口。在前端,我们除了根据用户的角色或其他特性来控制一些页面元素是否显示以外,也需要控制用户是否能够进入某些页面(例如通过直接输入URL的方式直接进入)。要控制是否显示,我们可以使用 *ngIf 、 [hidden] 等方式。而对于控制用户能否进入某个页面,Angular2的路由框架也提供了非常方便的方式来实现这个功能。

Angular2提供了2种组件, Guard 和 Resolve 。 Guard 顾名思义就是用来保护一个路径。可以用来判断用户只有在满足一定的条件的情况下才能打开这个路径对应的页面。 Resolve 用来在进入某个路径之前先获取数据。

Guard

Guard 其实是一系列接口,只要你实现了它的方法,配置了这些 Guard ,Angular路由框架就会根据这个方法返回的 true 或 false 来判断是否激活这个路由。它包括几种类型:

1、CanActivate

这种类型的 Guard 用来控制是否允许进入当前的路径。

2、CanActivateChild

这种类型的 Guard 用来控制是否允许进入当前路径的所有子路径。

3、CanDeactivate

用来控制是否能离开当前页面进入别的路径

4、CanLoad

用于控制一个异步加载的子模块是否允许被加载。

以 CanActivate 为例,这个接口的定义如下:

exportinterface CanActivate { canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean; }

这个接口定义了一个方法,当你实现这个接口,并把它配置到某一个路由上以后,当用户进入这个路由的路径之前,就会调用它里面的 canActivate() 方法,它第一个参数,就是将要激活的路由,第二个参数是路由器当前的状态。它返回一个布尔型的结果,或者是布尔型的 Promise 或 Observable 。

Resolve

这跟Angular1中ui-router库的 resolve 类似,就是用来在打开一个页面之前先获取数据,而不是进入页面以后再加载。这个接口中的方法,可以返回任意的对象,也可以返回一个 Promise ,或者 Observable

如果在一个路径上同时设置了 CanActivate 和 Resolve ,首先 CanActivate 接口的方法会被执行,当这个路由可以被激活时, Resolve 接口的方法才会被执行。

实例

下面,我们来通过一个比较完整的实例,来看看, CanActivate , CanActivateChild , CanDeactivate 和 Resolve 的用法。( CanLoad 将会在之后介绍子模块、异步加载的文章中再介绍)。这篇教程的源代码可以在这里 查看。

场景

我们还是用之前的教程 Angular2入门教程-2 实现TodoList App 中的实例。

我们先来看一看要解决的一些问题:

系统的默认页是home页面,这个页面不需要登录也可以打开。

登陆以后,管理员和用户分别进入不同的页面。

所有的todo模块的页面都需要用户角色,管理页面需要管理员角色

在进入任务列表页面之前,需要获取任务列表数据,而不是进入页面以后再获取数据。

当用户离开任务详情页时,提示是否确认要离开。

默认页面home

默认页面就是当用户直接打开你的网页域名,没有输入任何路径的情况下,默认打开的页面,在之前的教程已经讲过,这是在配置路由的时候,用 redirect 实现:

{ path: '', redirectTo: '/home', pathMatch: 'full' }

AuthService

首先我们需要一个权限验证的服务 AuthService ,除了用来进行登陆操作,还用于验证是否登陆,是否具有拥有某种角色。具体代码如下:

import{ Observable }from'rxjs/Observable'; import'rxjs/add/observable/of'; @Injectable() exportclassAuthService{ account: Account; // simulation to login. login(role: string): Observable<Account> { letaccount =newAccount(); account.id = 11; account.name = 'super man'; account.roles = [role]; this.account = account; returnObservable.of(account); } getAccount(): Account { returnthis.account; } isLogdedin(): boolean { returnthis.account &&this.account.id !=null; } hasRole(role: string): boolean { returnthis.account &&this.account.roles.includes(role); } }

在最上面我们注意到我们引入了 Observable 和它的一个方法 of 。这是由于我们的登陆操作一般都是去服务器端进行登陆验证,而使用 Http 服务从服务器端获取数据一般都是返回 Observable ,所以这里也使用 Observable 来返回登陆后的用户信息。我们引入 of 方法,是因为我们对 Observable 的操作都是需要什么操作符就引入什么,而不是直接引入所有的。

最后的 hasRole(role) 方法的用途是,我们可以在页面上通过 ngIf="hasRole('CUSTOMER')" 的方式来控制是否显示某个页面元素。

原先的todo路由定义

之前todo模块的路由是这样:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wypddp.html