Saltar al contenido

Guardias de ruta en Flutter

Al fin después de tanto luchar pudimos dar con el resultado de esta impedimento que muchos usuarios de este sitio web presentan. Si tienes algún dato que aportar no dudes en dejar tu conocimiento.

Solución:

Yo también estaba tropezando con este problema y terminé usando un FutureBuilder para esto. Echa un vistazo a mis rutas:

final routes = 
  '/': (BuildContext context) => FutureBuilder(
    // This is my async call to sharedPrefs
    future: AuthProvider.of(context).authState$.skipWhile((_) => _ == null).first,
    builder: (BuildContext context, AsyncSnapshot snapshot) 
      switch(snapshot.connectionState) 
        case ConnectionState.done:
          // When the future is done I show either the LoginScreen 
          // or the requested Screen depending on AuthState
          return snapshot.data == AuthState.SIGNED_IN ? JobsScreen() : LoginScreen()
        default:
          // I return an empty Container as long as the Future is not resolved
          return Container();
      
    ,
  ),
;

Si desea reutilizar el código en varias rutas, puede ampliar FutureBuilder.

No creo que exista un mecanismo de protección de ruta per se, pero puede hacer lógica en el main función antes de cargar la aplicación, o utilice la onGenerateRoute propiedad de un MaterialApp. Una forma de hacerlo en su caso es esperar una función asincrónica que verifique si el usuario está conectado antes de cargar la ruta inicial. Algo como

main() 
  fetchUser().then((user) 
    if (user != null) runApp(MyApp(page: 'home'));
    else runApp(MyApp(page: 'login'));
  );

Pero también puede estar interesado en la forma en que lo hace la aplicación Shrine. Tienen la página de inicio de sesión como ruta inicial en cualquier caso y la eliminan si el usuario ha iniciado sesión. De esa manera, el usuario ve la página de inicio de sesión hasta que se haya determinado si inicia sesión o no. He incluido el fragmento relevante a continuación. .

class ShrineApp extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    return MaterialApp(
      title: 'Shrine',
      home: HomePage(),
      initialRoute: '/login',
      onGenerateRoute: _getRoute,
    );
  

  Route _getRoute(RouteSettings settings) 
    if (settings.name != '/login') 
      return null;
    

    return MaterialPageRoute(
      settings: settings,
      builder: (BuildContext context) => LoginPage(),
      fullscreenDialog: true,
    );
  

Si no desea que vean la página de inicio de sesión en absoluto si están registrados, utilice el primer enfoque y podrá controlar la pantalla de inicio que se muestra antes. runApp tiene una interfaz de usuario explorando esta respuesta.

Se me ocurrió la siguiente solución para un proyecto web, que me permite introducir fácilmente rutas protegidas sin tener que preocuparme de que un usuario no autorizado pueda acceder a información confidencial.

La clase GuardedRoute tiene este aspecto:

import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:kandabis_core/core.dart' as core;

Widget _defaultTransitionsBuilder(
    BuildContext context,
    Animation animation,
    Animation secondaryAnimation,
    Widget child) 

    return child;


class GuardedRoute extends PageRouteBuilder 

    GuardedRoute(
        @required final String guardedRoute,
        @required final String fallbackRoute,
        @required final Stream guard,
        @required final core.Router router,
        final RouteTransitionsBuilder transitionsBuilder = _defaultTransitionsBuilder,
        final bool maintainState = true,
        final Widget placeholderPage,
    )
    : super(
        transitionsBuilder: transitionsBuilder,
        maintainState: maintainState,
        pageBuilder: (context, animation, secondaryAnimation) =>

            StreamBuilder(
                stream: guard,
                builder: (context, snapshot) 

                    if (snapshot.hasData) 

                        // navigate to guarded route
                        if (snapshot.data == true) 

                            return router.routes[guardedRoute](context);
                        

                        // navigate to fallback route
                        return router.routes[fallbackRoute](context);
                    

                    // show a placeholder widget while the guard stream has no data yet
                    return placeholderPage ?? Container();
                
            ),
    );

Usar la ruta vigilada es fácil. Puede definir una ruta protegida y una ruta alternativa (como una página de inicio de sesión). Guard es un Stream que decide si el usuario puede navegar a la ruta protegida. esta es mi clase de enrutador que muestra cómo usar la clase GuardedRoute:

class BackendRouter extends core.BackendRouter 

    BackendRouter(
        this._authenticationProvider,
        this._logger
        );

    static const _tag = "BackendRouter";

    core.Lazy> _navigatorKey =

        core.Lazy(() => GlobalKey());

    final core.AuthenticationProvider _authenticationProvider;
    final core.Logger _logger;

    @override
    Map get routes => 

        core.BackendRoutes.main: (context) => MainPage(),
        core.BackendRoutes.login: (context) => LoginPage(),
        core.BackendRoutes.import: (context) => ImportPage(),
    ;

    @override
    Route onGenerateRoute(RouteSettings settings) 

        if (settings.name == core.BackendRoutes.login) 

            return MaterialPageRoute(
                settings: settings,
                builder: routes[settings.name]
            );
        

        return _guardedRoute(settings.name);
    

    @override
    GlobalKey get navigatorKey => _navigatorKey();

    @override
    void navigateToLogin() 

        _logger.i(_tag, "navigateToLogin()");

        navigatorKey
            .currentState
            ?.pushNamed(core.BackendRoutes.login);
    

    @override
    void navigateToImporter() 

        _logger.i(_tag, "navigateToImporter()");

        navigatorKey
            .currentState
            ?.pushReplacement(_guardedRoute(core.BackendRoutes.import));
    

    GuardedRoute _guardedRoute(
         String route,
         
             maintainState = true,
             fallbackRoute = core.BackendRoutes.login,
         ) =>

         GuardedRoute(
             guardedRoute: route,
             fallbackRoute: fallbackRoute,
             guard: _authenticationProvider.isLoggedIn(),
             router: this,
             maintainState: maintainState,
             placeholderPage: SplashPage(),
         );

Y su clase de aplicación se ve así:

class BackendApp extends StatelessWidget 

    @override
    Widget build(BuildContext context) 

        // get router via dependency injection
        final core.BackendRouter router = di.get();

        // create app
        return MaterialApp(
            onGenerateRoute: (settings) => router.onGenerateRoute(settings),
            navigatorKey: router.navigatorKey,
        );
    

Sección de Reseñas y Valoraciones

Recuerda que te brindamos la opción de agregar una reseña si tropezaste tu impedimento a tiempo.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *