<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ## 一、路由守衛:當用戶滿足一定條件才被允許進入或者離開一個路由。 >[warning] 路由守衛場景: * 該用戶可能無權導航到目標組件。 * 可能用戶得先登錄(認證)。 * 在顯示目標組件前,你可能得先獲取某些數據。 * 在離開組件前,你可能要先保存修改。 * 你可能要詢問用戶:你是否要放棄本次更改,而不用保存它們? >[info] 路由守衛返回一個布爾值以控制路由: * 如果它返回`true`,導航過程會繼續 * 如果它返回`false`,導航過程就會終止,且用戶留在原地。 * 如果它返回`UrlTree`,則取消當前的導航,并且開始導航到返回的這個`UrlTree` >[danger] 守衛可以用同步的方式返回一個布爾值,但大多情況都是異步的,例如網絡請求,因此路由守衛可以返回一個Observable對象 或 Promise對象,并且路由器會等待這個可觀察對象被解析為`true`或`false`。 ## 二、路由守衛接口 >[info] 路由器可以支持多種守衛接口: * 用`CanActivate`來處理導航到某路由的情況。 * 用`CanActivateChild`來處理導航到某子路由的情況。 * 用`CanDeactivate`來處理從當前路由離開的情況. * 用`Resolve`在路由激活之前獲取路由數據。 * 用`CanLoad`來處理異步導航到某特性模塊的情況。 > 路由器會先按照從最深的子路由由下往上檢查的順序來檢查 CanDeactivate() 和 CanActivateChild() 守衛。 然后它會按照從上到下的順序檢查 CanActivate() 守衛。如果特性模塊是異步加載的,在加載它之前還會檢查 CanLoad() 守衛。 如果任何一個守衛返回 false,其它尚未完成的守衛會被取消,這樣整個導航就被取消了。 ### 1.CanActivate:要求認證(登錄認證、權限認證) 創建一個admin特征模塊:`ng generate module admin --routing` 創建admin特征模塊的子組件: * `ng generate component admin/admin-dashboard` * `content_copyng generate component admin/admin` * `content_copyng generate component admin/manage-crises` * `content_copyng generate component admin/manage-heroes` admin特征模塊的文件內容如下: ``` src/app/admin ├─admin │ ├─admin.component.css │ ├─admin.component.html │ └─admin.component.ts ├─admin-dashboard │ ├─admin-dashboard.component.css │ ├─admin-dashboard.component.html │ └─admin-dashboard.component.ts ├─manage-crises │ ├─manage-crises.component.css │ ├─manage-crises.component.html │ └─manage-crises.component.ts ├─manage-heroes │ ├─manage-heroes.component.css │ ├─manage-heroes.component.html │ └─manage-heroes.component.ts ├─admin.module.ts └─admin-routing.module.ts ``` >[info] src/app/admin/admin/admin.component.html文件內容 ``` <h3>ADMIN</h3> <nav> <a routerLink="./" routerLinkActive="active" [routerLinkActiveOptions]="{ exact: true }">Dashboard</a> <a routerLink="./crises" routerLinkActive="active">Manage Crises</a> <a routerLink="./heroes" routerLinkActive="active">Manage Heroes</a> </nav> <router-outlet></router-outlet> ``` > 路由鏈接中有一個斜杠/的路由,表示它能夠匹配admin特征模塊中的任何路由,但是只希望在訪問 Dashboard 路由時才激活該鏈接,往Dashboard 這個 routerLink 上添加另一個綁定 \[routerLinkActiveOptions\]="{ exact: true }",這樣導航到admin特征模塊時會激活Dashboard 路由而不會激活其他路由 (訪問admin特征模塊時激活Dashboard 路由) #### 無組件路由: 分組路由,而不需要組件 >[info] admin特征模塊下的路由配置文件: ``` const adminRoutes: Routes = [ { path: 'admin', component: AdminComponent, children: [ { path: '', children: [ { path: 'crises', component: ManageCrisesComponent }, { path: 'heroes', component: ManageHeroesComponent }, { path: '', component: AdminDashboardComponent } ] } ] } ]; @NgModule({ imports: [ RouterModule.forChild(adminRoutes) ], exports: [ RouterModule ] }) export class AdminRoutingModule {} ``` > `AdminComponent`的子路由,有**path**屬性和**children**屬性, 但它沒有使用**component**。代表這是一個無組件路由 > 這里是對`admin`路徑下的`危機中心`管理類路由進行分組,并不需要另一個僅用來分組路由的組件。 一個無組件的路由能讓守衛子路由變得更容易。 在app.module.ts中導入AdminModule并把它加入`imports`數組中來注冊這些管理類路由。 在app.component.html模板中添加admin特征模塊的導航鏈接 ``` <h1 class="title">Angular Router</h1> <nav> <a routerLink="/crisis-center" routerLinkActive="active">Crisis Center</a> <a routerLink="/heroes" routerLinkActive="active">Heroes</a> <a routerLink="/admin" routerLinkActive="active">Admin</a> <a [routerLink]="[{ outlets: { popup: ['compose'] } }]">Contact</a> </nav> <div [@routeAnimation]="getAnimationData(routerOutlet)"> <router-outlet #routerOutlet="outlet"></router-outlet> </div> <router-outlet name="popup"></router-outlet> ``` #### 使用CanActivate接口守衛admin特征模塊 >[danger] 目前admin特征模塊的路由對所有人都是開放的,這顯然不夠安全,使用CanActivate() 守衛,將正在嘗試訪問admin特征模塊的匿名用戶重定向到登錄頁,只有登錄的用戶才有權訪問 這是一個通用的守衛(假設另外一些特征模塊也要求已認證過的用戶才能訪問),所以可以在`auth`目錄下生成一個`AuthGuard`。 一、創建路由守衛 >[info] 在CLI輸入命令:ng generate guard auth/auth(路由守衛類名) 輸入命令后創建的路由守衛`src/app/auth/auth.guard.ts` ``` import { Injectable } from '@angular/core'; import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; @Injectable({ providedIn: 'root', }) export class AuthGuard implements CanActivate { canActivate( next: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean { console.log('AuthGuard#canActivate called'); return true; } } ``` 二、添加路由守衛 在`admin`特征模塊路由文件中引入`AuthGuard`類并添加`CanActivate()` 守衛 >[danger] canActivate可以指定多個守衛,值是一個數組。 ``` //引入路由守衛類 import { AuthGuard } from '../auth/auth.guard'; const adminRoutes: Routes = [ { path: 'admin', component: AdminComponent, canActivate: [AuthGuard], //添加canActivate路由守衛 children: [ { path: '', children: [ { path: 'crises', component: ManageCrisesComponent }, { path: 'heroes', component: ManageHeroesComponent }, { path: '', component: AdminDashboardComponent } ], } ] } ]; @NgModule({ imports: [ RouterModule.forChild(adminRoutes) ], exports: [ RouterModule ] }) export class AdminRoutingModule {} ``` 三、編寫路由守衛邏輯進行認證 創建一個服務進行授權認證,該服務能讓用戶登錄(模擬登陸),并且保存當前用戶的信息 >[info] 在CLI輸入命令:ng generate service auth/auth 輸入命令后創建的服務`src/app/auth/auth.service.ts` ``` import { Injectable } from '@angular/core'; import { Observable, of } from 'rxjs'; import { tap, delay } from 'rxjs/operators'; @Injectable({ providedIn: 'root', }) export class AuthService { isLoggedIn = false; // 存儲url,用于登錄后進行跳轉 redirectUrl: string; login(): Observable<boolean> { return of(true).pipe( delay(1000), tap(val => this.isLoggedIn = true) ); } logout(): void { this.isLoggedIn = false; } } ``` 在路由守衛中使用服務進行登錄驗證 ``` import { Injectable } from '@angular/core'; import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router'; import { AuthService } from './auth.service'; @Injectable({ providedIn: 'root', }) export class AuthGuard implements CanActivate { constructor(private authService: AuthService, private router: Router) {} canActivate( next: ActivatedRouteSnapshot, // ActivatedRouteSnapshot 包含了即將被激活的路由 state: RouterStateSnapshot): boolean { //RouterStateSnapshot 包含了該應用即將到達的狀態 let url: string = state.url; return this.checkLogin(url); } checkLogin(url: string): boolean { if (this.authService.isLoggedIn) { return true; } //存儲要跳轉到的url this.authService.redirectUrl = url; // 跳轉到登錄 this.router.navigate(['/login']); return false; } } ``` >[info] 創建一個登錄組件用于用戶登錄,登錄成功后將導航到原來的url。 ### 2.CanActivateChild:保護子路由 >[info] 使用CanActivateChild 路由守衛來保護子路由。 CanActivateChild 守衛和 CanActivate 守衛很像。 區別在于,CanActivateChild 會在任何子路由被激活之前運行。 一、擴展`AuthGuard`,添加`CanActivateChild `接口。 ``` import { Injectable } from '@angular/core'; import { CanActivate, Router, ActivatedRouteSnapshot, RouterStateSnapshot, CanActivateChild //添加CanActivateChild接口 } from '@angular/router'; import { AuthService } from './auth.service'; @Injectable({ providedIn: 'root', }) export class AuthGuard implements CanActivate, CanActivateChild { //繼承CanActivateChild 接口 constructor(private authService: AuthService, private router: Router) {} canActivate( route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean { let url: string = state.url; return this.checkLogin(url); } //實現canActivateChild路由邏輯 canActivateChild( route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean { return this.canActivate(route, state); } /* . . . */ } ``` 二、在特征路由中添加`canActivateChild`路由守衛 同樣把這個`AuthGuard`添加到“無組件的”管理路由,來同時保護它的所有子路由,而不是為每個路由單獨添加這個`AuthGuard`。 ``` const adminRoutes: Routes = [ { path: 'admin', component: AdminComponent, canActivate: [AuthGuard], children: [ { path: '', canActivateChild: [AuthGuard], //添加canActivateChild路由守衛 children: [ { path: 'crises', component: ManageCrisesComponent }, { path: 'heroes', component: ManageHeroesComponent }, { path: '', component: AdminDashboardComponent } ] } ] } ]; @NgModule({ imports: [ RouterModule.forChild(adminRoutes) ], exports: [ RouterModule ] }) export class AdminRoutingModule {} ``` ### 3.CanDeactivate:處理未保存的更改 一、創建一個守衛 >[info] 在CLI輸入命令:ng generate guard can-deactivate 輸入命令后創建的文件`src/app/can-deactivate.guard.ts` ``` import { Injectable } from '@angular/core'; import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; import { Observable } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class CanDeactivatesGuard implements CanActivate { canActivate( next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean { return true; } } ``` 二、實現CanDeactivate路由守衛邏輯 >[info]實現CanDeactivate路由守衛的邏輯,判斷表單的數據是否有改變,當數據有所改變用戶卻要離開頁面時提示用戶數據未保存 1.單獨為組件實現CanDeactivate守衛 ``` import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; import { CanDeactivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; import { CrisisDetailComponent } from './crisis-center/crisis-detail/crisis-detail.component'; @Injectable({ providedIn: 'root', }) export class CanDeactivateGuard implements CanDeactivate<CrisisDetailComponent> { canDeactivate( component: CrisisDetailComponent, //組件 route: ActivatedRouteSnapshot, state: RouterStateSnapshot ): Observable<boolean> | boolean { // 獲取危機中心的id console.log(route.paramMap.get('id')); //獲取當前url console.log(state.url); // 如果表單的值沒有改變,則繼續導航 if (!component.crisis || component.crisis.name === component.editName) { return true; } //彈出確認框 return component.dialogService.confirm('Discard changes?'); } } ``` 2.實現復用的CanDeactivate守衛 (1)在組件中實現CanDeactivate方法 ``` export class CrisisDetailComponent implements OnInit { crisis: Crisis; editName: string; constructor( private route: ActivatedRoute, private router: Router, public dialogService: DialogService ) {} //在組件中實現canDeactivate路由守衛的實現邏輯 canDeactivate(): Observable<boolean> | boolean { // 如果表單的值沒有改變,則繼續導航 if (!component.crisis || component.crisis.name === component.editName) { return true; } //彈出確認框 return component.dialogService.confirm('Discard changes?'); } } ``` (2)在CanDeactivateGuard中調用組件的CanDeactivate方法 ``` import { Injectable } from '@angular/core'; import { CanDeactivate } from '@angular/router'; import { Observable } from 'rxjs'; export interface CanComponentDeactivate { canDeactivate: () => Observable<boolean> | Promise<boolean> | boolean; } @Injectable({ providedIn: 'root', }) export class CanDeactivateGuard implements CanDeactivate<CanComponentDeactivate> { canDeactivate(component: CanComponentDeactivate) { //組件中是否有canDeactivate方法,有就執行沒有返回true return component.canDeactivate ? component.canDeactivate() : true; } } ``` 三、在路由配置文件中添加CanDeactivate守衛 ``` import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { CrisisCenterHomeComponent } from './crisis-center-home/crisis-center-home.component'; import { CrisisListComponent } from './crisis-list/crisis-list.component'; import { CrisisCenterComponent } from './crisis-center/crisis-center.component'; import { CrisisDetailComponent } from './crisis-detail/crisis-detail.component'; import { CanDeactivateGuard } from '../can-deactivate.guard'; import { CrisisDetailResolverService } from './crisis-detail-resolver.service'; const crisisCenterRoutes: Routes = [ { path: '', component: CrisisCenterComponent, children: [ { path: '', component: CrisisListComponent, children: [ { path: ':id', component: CrisisDetailComponent, canDeactivate: [CanDeactivateGuard],//添加canDeactivate路由守衛 resolve: { crisis: CrisisDetailResolverService } }, { path: '', component: CrisisCenterHomeComponent } ] } ] } ]; @NgModule({ imports: [ RouterModule.forChild(crisisCenterRoutes) ], exports: [ RouterModule ] }) export class CrisisCenterRoutingModule { } ``` ### 4.Resolve: 預先獲取組件數據 >[warning] resolve:在進入路由之前去服務器讀數據,把需要的數據都讀好以后,帶著這些數據進到路由里,立刻就把數據顯示出來。 一、創建服務獲取數據 >[info] 在CLI輸入命令:ng generate service crisis-center/crisis-detail-resolver 輸入命令后創建的服務`src/app/crisis-center/crisis-detail-resolver.service.ts` ``` import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root', }) export class CrisisDetailResolverService { constructor() { } } ``` >[info] 使用服務獲取數據: ``` import { Injectable } from '@angular/core'; import { Router, Resolve, RouterStateSnapshot, ActivatedRouteSnapshot } from '@angular/router'; import { Observable, of, EMPTY } from 'rxjs'; import { mergeMap, take } from 'rxjs/operators'; import { CrisisService } from './crisis.service'; import { Crisis } from './crisis'; @Injectable({ providedIn: 'root', }) export class CrisisDetailResolverService implements Resolve<Crisis> { constructor(private cs: CrisisService, private router: Router) {} resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Crisis> | Observable<never> { let id = route.paramMap.get('id'); //獲取路由傳遞的參數 //獲取數據,通常會發起網絡請求獲取數據,此處只是模擬 return this.cs.getCrisis(id).pipe( take(1), mergeMap(crisis => { if (crisis) { return of(crisis); } else { //id not found this.router.navigate(['/crisis-center']); return EMPTY; } }) ); } } ``` 二、添加Resolve路由守衛 ``` import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { CrisisCenterHomeComponent } from './crisis-center-home/crisis-center-home.component'; import { CrisisListComponent } from './crisis-list/crisis-list.component'; import { CrisisCenterComponent } from './crisis-center/crisis-center.component'; import { CrisisDetailComponent } from './crisis-detail/crisis-detail.component'; import { CanDeactivateGuard } from '../can-deactivate.guard'; import { CrisisDetailResolverService } from './crisis-detail-resolver.service'; const crisisCenterRoutes: Routes = [ { path: 'crisis-center', component: CrisisCenterComponent, children: [ { path: '', component: CrisisListComponent, children: [ { path: ':id', component: CrisisDetailComponent, canDeactivate: [CanDeactivateGuard], resolve: { crisis: CrisisDetailResolverService //添加resolve路由守衛,CrisisDetailResolverService是獲取數據的服務 } }, { path: '', component: CrisisCenterHomeComponent } ] } ] } ]; @NgModule({ imports: [ RouterModule.forChild(crisisCenterRoutes) ], exports: [ RouterModule ] }) export class CrisisCenterRoutingModule { } ``` 三、組件接收數據 ``` ngOnInit() { this.route.data .subscribe((data: { crisis: Crisis }) => { this.editName = data.crisis.name; this.crisis = data.crisis; }); } ``` ### 5.CanLoad接口:保護對特性模塊的未授權加載 >[info] 目前已使用CanActivate路由守衛保護admin特征模塊,它會阻止未授權的用戶訪問admin模塊,。如果用戶未登錄,它會跳轉到登錄頁。但是admin模塊仍被加載了,因此需要使用CanLoad路由守衛接口實現已登錄的情況才加載admin模塊 一、實現canLoad路由守衛 打開` auth.guard.ts`,從 `@angular/router` 中導入` CanLoad `接口。 把它添加到 AuthGuard 類的 implements 列表中。 然后實現 canLoad,代碼如下: > 路由器會把 canLoad() 方法的 route 參數設置為準備訪問的目標 URL。 如果用戶已經登錄了,checkLogin() 方法就會重定向到那個 URL。 ``` canLoad(route: Route): boolean { let url = `${route.path}`; //url return this.checkLogin(url); } ``` 二、添加canLoad路由守衛 ``` { path: 'admin', loadChildren: './admin/admin.module#AdminModule', canLoad: [AuthGuard] }, ```
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看