Angular の Guard で別のページに遷移させる
Angular の Guard といえば、ページ遷移前に認証情報を取得したり、ページを表示出来るかの権限チェックをしたり、、、ページを表示する前の前処理を色々行う機能です。 Angular 6 までは、 Guard はページを表示できるできないの boolean の値を返すことしかできませんでしたが、 Angular 7 からは違うページを表示するために URL を返せるようになりました。
試した環境
この記事は以下のAngularバージョンで作成されています。
_ _ ____ _ ___ / \ _ __ __ _ _ _| | __ _ _ __ / ___| | |_ _| / △ \ | '_ \ / _` | | | | |/ _` | '__| | | | | | | / ___ \| | | | (_| | |_| | | (_| | | | |___| |___ | | /_/ \_\_| |_|\__, |\__,_|_|\__,_|_| \____|_____|___| |___/ Angular CLI: 7.3.5 Node: 10.15.1 OS: darwin x64 Angular: 7.2.8 ... animations, common, compiler, compiler-cli, core, forms ... language-service, platform-browser, platform-browser-dynamic ... router Package Version ----------------------------------------------------------- @angular-devkit/architect 0.13.5 @angular-devkit/build-angular 0.13.5 @angular-devkit/build-optimizer 0.13.5 @angular-devkit/build-webpack 0.13.5 @angular-devkit/core 7.3.5 @angular-devkit/schematics 7.3.5 @angular/cli 7.3.5 @ngtools/webpack 7.3.5 @schematics/angular 7.3.5 @schematics/update 0.13.5 rxjs 6.3.3 typescript 3.2.4 webpack 4.29.0
Guard の作成
Guard は標準で Angular CLI に生成コマンドが含まれていますので、サクッと作成します。
ng-guard-sample tnakatani$ ng generate guard authorize ? Which interfaces would you like to implement? CanActivate CREATE src/app/authorize.guard.ts (461 bytes)
標準で生成される Guard の実装はこんな感じです。テンプレートを作ってくれるだけでもとてもありがたいです。
また Angular 6 時代とは異なり、戻りの型として UrlTree
を返せるようになっていることが分かります。
import { Injectable } from '@angular/core'; import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree } from '@angular/router'; import { Observable } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class AuthorizeGuard implements CanActivate { canActivate( next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree { return true; } }
Guard から別のページに遷移させる
Guard から true/false
ではなく UrlTree
を返すことで、本来の遷移先 URL ではなく別の URL へ遷移させることができます。
UrlTree
は Router.createUrlTree
から生成します。生成時のパラメーターは Router で遷移するときと同じです。
例えばランダムに 1/2 の確率でログインページに飛ばすような雑な Guard だと、次の実装のようになります。
import { Injectable } from '@angular/core'; import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree, Router } from '@angular/router'; import { Observable } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class AuthorizeGuard implements CanActivate { constructor(private readonly _router: Router) { } canActivate( next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree { const value = Math.random(); if (value > 0.5) { return true; } return this._router.createUrlTree(['authorize', 'login'], { queryParams: { reason: 'random' } }); } }