[NGX]Angular路由守衛初探(1)

我愛吃南瓜發表於2019-03-01

何時使用

  1. 使用者無權導航到目標元件
  2. 使用者得先登入認證
  3. 顯示目標元件前,需要先獲得某些資料
  4. 離開元件前,需要先儲存修改,需要詢問使用者是否放棄修改

使用方法

  1. 路由守衛返回一個值Observable / Promise,以控制路由器的行為:

    • 返回true,導航繼續
    • 返回false,導航終止
  2. 一般專案都會有多層路由和模組懶載入,因此在路由的每個層次上,我們都可以設定多個守衛。路由檢查順序:

    • 從最深的子路由從下往上檢查CanDeactivate()和CanActivateChild()守衛。
    • 自上而下檢查CanActivate()守衛。

    在上面的過程中,如果模組是lazyLoad的,載入之前還會檢查CanLoad()守衛。

    檢查過程中任何一個守衛返回false,其他未完成的守衛會被取消,整個導航就會被取消。

  3. 幾個路由守衛

    守衛 功能
    CanActivate 導航某路由的情況
    CanActivateChild 導航某子路由的情況
    CanDeactivate 從當前路由離開的情況
    Resolve 路由啟用前獲取路由資料
    CanLoad 非同步導航到某特性模組(懶載入)

CanActivate: 要求認證

一般用來管理訪問者是否有許可權訪問該特性模組或元件;

在根模組下面建立一個service資料夾,用來存放公共的service

// /src/app/service/auth-guard.service.ts
import { Injectable } from `@angular/core`;
import { CanActivate, Router } from `@angular/router`;
import { HttpClient } from `@angular/common/http`;
import { Observable } from `rxjs/Observable`;

@Injectable()
export class AuthGuardService implements CanActivate {
    constructor(private router: Router, private http: HttpClient) {}

    canActivate(): Observable<any> {
        console.log(`canActivate goes here`);
        // 這裡返回一個Observable<boolean>
        return this.http.get(`/api/isLogin`).map(item => {
            return item[`success`];
        });
    }
}
複製程式碼

然後開啟根模組的routing模組, 注入AuthGuardService:

// /src/app/app-routing.module.ts
import { NgModule } from `@angular/core`;
import { RouterModule, Routes } from `@angular/router`;
import { AuthGuardService } from `./service/auth-guard.service`;

const appRoutes: Routes = [
    { path: `view`, loadChildren: `app/core/main/main.module#MainModule`, canActivate: [AuthGuardService] },
    { path: `schedule`, loadChildren: `app/core/schedule/schedule.module#ScheduleModule` },
    { path: `system`, loadChildren: `app/core/system/system.module#SystemModule` },
    { path: ``, redirectTo: `view/order`, pathMatch: `full` },
];

@NgModule({
    imports: [RouterModule.forRoot(appRoutes, {
        enableTracing: true, // <-- debugging purposes only
    })],
    exports: [RouterModule],
    providers: [AuthGuardService]
})
export class AppRoutingModule {}
複製程式碼

以上會使整個模組的訪問受限,如果要設定特定元件是否可以訪問,則需要注入到相應的特性模組的routing模組,方法相同

CanDeactivate: 處理未儲存的修改

用非同步的方式等待伺服器答覆之前先停止導航,canDeactivate方法提供了當前元件,當前ActivatedRoute個RouterStateSnapshot例項。
下面這個Guard可以被所有元件複用

// /src/app/service/can-deactivate.service.ts
import { Injectable } from `@angular/core`;
import { CanDeactivate } from `@angular/router`;
import { CanDeactivate,
         ActivatedRouteSnapshot,
         RouterStateSnapshot }  from `@angular/router`;


export interface CanComponentDeactivate {
    canDeactivate: () => Observable<boolean> | Promise<boolean> | boolean;
}

@Injectable()
export class CanDeactivateService implements CanDeactivate<CanComponentDeactivate> {
    canDeactivate (
        component: CanComponentDeactivate,
        route: ActivatedRouteSnapshot,
        state: RouterStateSnapshot
    ) {
        console.log(`Deactivate goes here`, component);
        return component.canDeactivate ? component.canDeactivate() : true;
    }
}
複製程式碼

當然也可以單獨為某個元件建立屬於他自己的canDeactivate-guard,建立完guard後,我們需要為元件建立他的canDeactivate()方法,這個方法返回一個Observable或Promise或boolean,最後加給routing模組對應route的canDeactivate陣列中即可;

相關文章