Flutter の Navigation 2.0 と AutoRoute で画面遷移時に認証状態を確認する
auto_route の AutoRouteGuard を使い、画面遷移のタイミングで認証状態を確認して未認証なら認証画面へ送る方法です。riverpod で DI している場合も扱っています。
- 公開日
この記事は別サイトにも掲載しています。 https://iganin.hatenablog.com/entry/2021/08/24/215355
tl;dr;
- 画面遷移時の認証状態を AutoRoute ライブラリの AutoRouteGuard を使って確認する
- 認証していない場合は認証画面に遷移させるなどもできる
- riverpod で DI している場合でも対応できる
書くこと
- auto_route + riverpod での画面遷移時の認証状態確認方法
書かないこと
- auto_route の詳しい使用方法
- riverpod の詳しい使用方法
内容
アプリを作成していると画面遷移時に認証状態を確認し、認証していない場合は認証画面に遷移させる、もしくは認証画面を表示したい場合がある。
認証していなければ使用できないアプリケーションはもちろんだが、通常の画面は認証なしでも使用でき、購入画面以降では認証が必須というような場合もありえる。
以下で、auto_route と riverpod でそのような対応を行う方法を記載する。
※ Web アプリだとどの画面に遷移してくるかわからないため、上記対応は必須のはず。
auto_route
Flutter の画面遷移関連のライブラリ。
下記のように記載することで、router.push(XxxRoute()) や router.pop() で画面遷移できる。とても便利。
@AdaptiveAutoRouter(
replaceInRouteName: 'Page,Route',
routes: <AutoRoute>[
AutoRoute(path: '/', page: InitialPage, initial: true),
AutoRoute(path: '/sign_in', page: SignInPage),
AutoRoute(path: '/sign_up', page: SignUpPage),
],
)
class $Router {}
class App extends HookWidget {
@override
Widget build(BuildContext context) {
return MaterialApp.router(
~~~~~~
routeInformationParser: router.defaultRouteParser(),
routerDelegate: router.delegate(),
~~~~~~
}
画面遷移時に認証状態の確認処理を挟む
auto_route に含まれている AutoRouteGuard を使用する。
class AuthGuard extends AutoRouteGuard {
@override
Future<void> onNavigation(
NavigationResolver resolver,
StackRouter router,
) async {
final isAuthenticated = await _isAuthenticated();
if (isAuthenticated) {
resolver.next(true);
} else {
// 場合によってはここで再認証処理をかけて、結果次第で画面遷移をするかどうか決めると良さそう
router.replaceAll([SignInRoute()]);
resolver.next(false);
}
}
}
AutoRouteGuard を定義した上で、AdaptiveAutoRouter の AutoRoute の guards 引数に Guard のクラスを記載すると、該当の画面に遷移する前に Guard の onNavigation が呼ばれるようになる。
@AdaptiveAutoRouter(
replaceInRouteName: 'Page,Route',
routes: <AutoRoute>[
AutoRoute(path: '/', page: InitialPage, initial: true, guards: [AuthGuard]),
AutoRoute(path: '/', page: SignInPage),
AutoRoute(path: '/', page: SignUpPage),
],
)
class $Router {}
ここで、引数などをどのように渡すのかという疑問が湧くが、AdaptiveAutoRouter から build_runner で生成されたクラスに使用している guard を引数としたコンストラクタが自動生成されるみたい。 したがって上記の Router を初期化しようとすると下記のようになる。
Router(authGuard: AuthGuard());
riverpod を組み込む
上記のように Router の初期化時に Guard を生成して渡すので、riverpod による DI も容易にできる。
final authGuardProvider = Provider((ref) => AuthGuard(ref.read));
class AuthGuard extends AutoRouteGuard {
AuthGuard(this._read);
final Reader _read;
AuthRepositoryBase get _authRepository => _read(authRepositoryProvider);
~~~~
}
class App extends HookWidget {
App({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final authGuard = useProvider(authGuardProvider);
final router = router(authGuard: authGuard);
~~~~
}
~~~~
}
その他
- guard を認証状態の確認に使用するのは、auto_route の README に記載もあったので推奨の方法なのだと思う。
guards: []の形で複数渡せるので、一覧 - 詳細 の画面があった際に詳細画面に遷移したときに必要な情報がないから一覧に遷移させる、といったこともできそう。