5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

記事の概要

Angularで認証済みの場合のみ遷移させたい画面があり、ルーティングにGuardを適用するためにGuardクラスを作成したところ、implementsしているCanActivateがDeprecatedでマークされていることに気づきました。
調べてみると、Angular15.2からクラスベースのルートGuardは非推奨になっていることがわかりました。
代わりに関数ベースのGuardを使うことが推奨されていますが、日本語の情報が少なかったため書き方を備忘としてメモしておきます。
ただし関数ベースのGuardといっても全種類ではなくCanActivateFnに限っての説明となります。

先に結論:書き方

関数ベースGuardの実装サンプル:

guards.ts
export const authGuard: CanActivateFn = () => {
  // 認証管理サービスのinject
  const authService = inject(AuthService);
  // Routerのinject
  const router = inject(Router);
  if (authService.isAuthenticated()) {
    // 認証済みのため(認証後画面への)ナビゲーションOK
    return true;
  } else {
    // 認証未済のため認証ページに飛ばす
    return router.parseUrl('auth');
  }
};
  • ~.routes.tsに直接定義してももちろん大丈夫です。
  • CanActivateFnのパラメータroute: ActivatedRouteSnapshot, state: RouterStateSnapshotは非使用のため省略しています。

Routes定義の実装サンプル:

app.routes.ts
export const routes: Routes = [
  {
    path: 'after-auth', // 認証後ページ
    loadComponent: () => import('./pages/after-auth/after-auth.page').then(m => m.AfterAuthPage),
    canActivate: [authGuard] // Guardの登録
  },
  {
    path: 'auth', // 認証ページ
    loadComponent: () => import('./pages/auth/auth.page').then(m => m.AuthPage),
  }
];

CanActivate:に配列でGuardを登録したら実装完了です。

CanAcvivateFnについて

CanAcvivateの代わりに実装するべきCanActivateFnについて見てみます。

型エイリアスはこのようになっています。基本的にはbooleanUrlTree(orこれらのObservable, Promise)を返す関数を実装すれば良いです。
パラメータのActivatedRouteSnapshot, RouterStateSnapshotは必須ではありません。

type CanActivateFn = (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree;

説明も見てみます。

If all guards return true, navigation continues. If any guard returns false, navigation is cancelled. If any guard returns a UrlTree, the current navigation is cancelled and a new navigation begins to the UrlTree returned from the guard.

「全てのguardがtrueを返した場合はナビゲーション続行。いずれかのguardがfalseを返したらナビゲーションはキャンセル。いずれかのguardがUrlTreeを返したら、それまでのナビゲーションはキャンセルされてUrlTreeへのナビゲーションがスタートする。」
・・・ということのようです。
元々のナビゲーションを許容する場合は単にtrueを返却すれば良いです。
一方で、元々のナビゲーションをキャンセルする場合、代わりに遷移させたいパスがあることがほとんどだと思います。
この場合の実装として、例えば以下のような感じで紹介している記事を見かけます。

/** 中略 */
const router = inject(Router)
if (canNavigate()) {
  return true;
else {
  // 代わりのパスにナビゲートした上で元々のナビゲーションはキャンセル
  router.navigate(['auth']);
  return false;
}

Router.navigateした上でfalseを返すこれでも動きますが、副作用を起こしている感が若干キレイじゃない気がしてしまいます。 (関数ベースだと特に)
代わりにUrlTreeを返す(Router.parseUrl())方がキレイに同じことを実現できるとこちらの記事で知ったため、サンプル実装でもそうしています。

/** 中略 */
const router = inject(Router)
if (canNavigate()) {
  return true;
else {
  // 代わりのパスにナビゲートした上で元々のナビゲーションはキャンセル
  return router.parseUrl('auth');
}

おまけ:UrlTreeについて

UrlTreeというクラスについて聞いたことが無かったためついでに少し調べてみました。

UrlTree is a data structure that provides a lot of affordances in dealing with URLs

「UrlTreeはURLに関する様々な利便性を提供するデータ構造」のようです。
Usage notesがとてもわかりやすいため引用します。

@Component({templateUrl:'template.html'})
class MyComponent {
  constructor(router: Router) {
    const tree: UrlTree =
      router.parseUrl('/team/33/(user/victor//support:help)?debug=true#fragment');
    const f = tree.fragment; // return 'fragment'
    const q = tree.queryParams; // returns {debug: 'true'}
    const g: UrlSegmentGroup = tree.root.children[PRIMARY_OUTLET];
    const s: UrlSegment[] = g.segments; // returns 2 segments 'team' and '33'
    g.children[PRIMARY_OUTLET].segments; // returns 2 segments 'user' and 'victor'
    g.children['support'].segments; // return 1 segment 'help'
  }
}

様々なプロパティによって、パラメータなどURLを構成するパーツにアクセスできるようです。
また、UrlTreeを作成する手段としていくつかあるようで:

  • RouterクラスのparseUrl(url: string): UrlTree;はURL文字列をシンプルにパースしてUrlTreeを作成できるようです。( https://angular.jp/api/router/Router#parseurl
  • 同じくRouterクラスのcreateUrlTree(commands: any[], navigationExtras?: UrlCreationOptions): UrlTree;はより柔軟にUrlTreeを組み立てられるようです。( https://angular.jp/api/router/Router#createurltree
    パラメータ等を付与したURLに遷移させる場合はこちらを使うのが便利かと思いました。

まとめ

関数ベースGuard(CanActivateFn)の実装方法とUrlTreeについて紹介しました。
最近のAngularやRxJSで非推奨になっている機能や代わりに推奨されている書き方について、意外と日本語の記事が少なかったりするため、少しでもこの記事が役に立てば嬉しいです。

参考資料

5
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?