淺談Angular路由守衛(wèi)
引言
在企業(yè)應(yīng)用中權(quán)限、復(fù)雜頁多路由數(shù)據(jù)處理、進(jìn)入與離開路由數(shù)據(jù)處理這些是非常常見的需求。
當(dāng)希望用戶離開一個正常編輯頁時,要中斷并提醒用戶是否真的要離開時,如果在Angular中應(yīng)該怎么做呢?
其實(shí)Angular路由守衛(wèi)屬性可以幫我們做更多有意義的事,而且非常簡單。
什么是路由守衛(wèi)?
Angular 的 Route
路由參數(shù)中除了熟悉的 path
、component
外,還包括四種是否允許路由激活與離開的屬性。
canActivate
控制是否允許進(jìn)入路由。
canActivateChild
等同 canActivate,只不過針對是所有子路由。
canDeactivate
控制是否允許離開路由。
canLoad
控制是否允許延遲加載整個模塊。
例如:
{ path: 'logics', loadChildren: './logics/logics.module#LogicsModule', canLoad: [ AuthGuard ] }
這四個屬性非常好理解,而且作用各自不同。然后當(dāng)進(jìn)入與離開能夠有效控制權(quán)時,對于前面我提到的若干問題,就可以非常好的處理。
如何創(chuàng)建?
四個屬性雖然名稱不同,但其基本的使用方式非常相近。四種不同守衛(wèi)方式有者四個不同的接口與之相對應(yīng)。
屬性名 | 接口名 |
---|---|
canActivate | CanActivate |
canActivateChild | CanActivateChild |
canDeactivate | CanDeactivate<TComponent> |
canLoad | CanLoad |
canDeactivate
需要指明具體的組件類名以外,其他接口只是將首字母大寫而已。假定需要一個某個角色才能訪問某些路由,就需要一個 CanActivate
守衛(wèi)類。
@Injectable() export class CanAdminProvide implements CanActivate { constructor(private userSrv: UserService, private msg: NzMessageService) {} canActivate( route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean | Observable<boolean> | Promise<boolean> { return new Observable((observer) => { // 擁有 `admin` 角色 if (this.userSrv.hasRole('admin')) { observer.next(true); observer.complete(); return; } this.msg.error('授權(quán)不足'); observer.next(false); observer.complete(); }); } }
每種接口要都需要相應(yīng)的實(shí)現(xiàn)某個方法,就上而論,繼承 CanActivate 并實(shí)現(xiàn)一個叫 canActivate 的方法;且返回一個布爾類型的值。
四種類型守衛(wèi)接口都返回一個布爾類型值,其實(shí)從這四種參數(shù)的名稱 can 開頭就不然理解。
最后,把它運(yùn)用到相應(yīng)的路由上即可,例如:
{ path: 'admin', component: GuardAdminComponent, canActivate: [ CanAdminProvide ] }
當(dāng)然,別忘記注冊 CanAdminProvide 類。
一些實(shí)踐
離開時提醒
四種守衛(wèi)只有一種離開類型 canDeactivate
,因此:
@Injectable() export class CanLeaveProvide implements CanDeactivate<GuardComponent> { constructor (private confirmSrv: NzModalService) {} canDeactivate( component: GuardComponent, currentRoute: ActivatedRouteSnapshot, currentState: RouterStateSnapshot, nextState?: RouterStateSnapshot): boolean | Observable<boolean> | Promise<boolean> { return new Observable((observer) => { this.confirmSrv.confirm({ title: '確認(rèn)要離開嗎?', content: '你已經(jīng)填寫了部分表單離開會放棄已經(jīng)填寫的內(nèi)容。', okText: '離開', cancelText: '取消', onOk: () => { observer.next(true); observer.complete(); }, onCancel: () => { observer.next(false); observer.complete(); } }); }); } }
這里返回的是一個 Observable
類型,意味者,在方法體內(nèi)可以做任何事,只需要在結(jié)果中使用:
// 允許 observer.next(true); // 或拒絕 // observer.next(false); observer.complete();
來處理 Observable 的結(jié)果,就完成了整個流程。倘若,用戶按瀏覽器后退或路由至其他頁面時,會先收到一個提醒。
上面使用的 ng-zorro-antd 的確認(rèn)對話框來提醒用戶是否需要離開,若選擇【離開】則跳轉(zhuǎn)至目標(biāo)路由,反之保留當(dāng)前路由狀態(tài)。
角色受限
這是再正常不過的功能,若用戶進(jìn)入一個未授權(quán)的路由時,甚至是某個遲延加載模塊下所有路由;若用戶無權(quán)限時,如何提醒用戶。
此時 canActivate、canLoad 就有用了。假定管理員角色才能加載管理模塊下所有管理功能以及某個管理頁面,基于接口多繼承的特性,可以同時繼承這兩個接口。
@Injectable() export class CanAuthProvide implements CanActivate, CanLoad { constructor(private userSrv: UserService, private msg: NzMessageService) {} check(): Observable<boolean> { return new Observable((observer) => { if (this.userSrv.isLogin) { observer.next(true); observer.complete(); return; } this.msg.error('權(quán)限不足'); observer.next(false); observer.complete(); }); } canActivate( route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean | Observable<boolean> | Promise<boolean> { return this.check(); } canLoad(route: Route): boolean | Observable<boolean> | Promise<boolean> { return this.check(); } }
因此,一個類中具有兩種不同守衛(wèi)的能力,更對于代碼組織也更優(yōu)雅。同樣,需要運(yùn)用到相應(yīng)的路由當(dāng)中。
{ path: 'auth', component: GuardAuthComponent, canActivate: [ CanAuthProvide ] }, { path: 'admin', loadChildren: './admin/admin.module#AdminModule', canLoad: [ CanAuthProvide ] }
此后,若一個普通員工賬號要想進(jìn)入(哪怕瀏覽器地址欄錄入)未授權(quán)的路由 /auth 會提示 權(quán)限不足 的字樣。
總結(jié)
路由守衛(wèi)對于權(quán)限控制非常便利,當(dāng)然其粒度當(dāng)然只能在頁面層級。倘若需要對按鈕粒度也只能利用指令的方式,而二者的結(jié)合可以極大的改善權(quán)限控制埋點(diǎn)的代碼量。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Angular實(shí)現(xiàn)較為復(fù)雜的表格過濾,刪除功能示例
這篇文章主要介紹了Angular實(shí)現(xiàn)較為復(fù)雜的表格過濾,刪除功能,結(jié)合實(shí)例形式分析了AngularJS針對表格的排序、查詢匹配、頁面元素屬性動態(tài)修改等相關(guān)操作技巧,需要的朋友可以參考下2017-12-12AngularJS中$apply方法和$watch方法用法總結(jié)
這篇文章主要介紹了AngularJS中$apply方法和$watch方法用法,結(jié)合實(shí)例形式總結(jié)分析了$apply方法和$watch方法的功能、參數(shù)含義、使用技巧與相關(guān)注意事項(xiàng),需要的朋友可以參考下2016-12-12Angularjs實(shí)現(xiàn)數(shù)組隨機(jī)排序的方法
今天小編就為大家分享一篇Angularjs實(shí)現(xiàn)數(shù)組隨機(jī)排序的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-10-10Angular使用ControlValueAccessor創(chuàng)建自定義表單控件
這篇文章主要介紹了Angular使用ControlValueAccessor創(chuàng)建自定義表單控件,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-03-03關(guān)于angular表單動態(tài)驗(yàn)證的一種新思路分享
在Angular?中不管是模板驅(qū)動表單還是響應(yīng)式表單,對于動態(tài)創(chuàng)建表單的支持都很好,下面這篇文章主要給大家介紹了關(guān)于angular表單動態(tài)驗(yàn)證的一種新思路,需要的朋友可以參考下2022-03-03