【问题标题】:How to handle authenticated routes and their redirects after successful auth?认证成功后如何处理认证路由及其重定向?
【发布时间】:2021-06-18 18:33:12
【问题描述】:

Flutter Web(Navigator 2.0/Router API): 认证成功后如何处理认证路由及其重定向?

例如 我的系统上有这些路线

/book/xyz (authenticated user)
/author/abc/book/xyz (authenticated user)
/authentication (non-authenticated user)
/info (non-authenticated user)

如果用户直接打开这个网址,我想要求用户先登录,那时路由将被重定向到..

/authentication

登录后,我希望用户浏览之前打开的 URL(如果还有其他主页)。

似乎这种事情可能会有所帮助,任何想法 - 我们如何才能实现类似的事情? https://stackoverflow.com/a/43171515/2145844

我已经为 Navigation 2.0 / Router API 尝试了一些示例,是的,我可以稍微理解这些概念..

一些参考资料,我看过..

https://medium.com/flutter/learning-flutters-new-navigation-and-routing-system-7c9068155ade https://github.com/orestesgaolin/navigator_20_example https://github.com/flutter/flutter/tree/master/dev/benchmarks/test_apps/stocks

【问题讨论】:

    标签: flutter navigation flutter-web flutter-navigation


    【解决方案1】:

    这里是如何使用 VRouter >=1.2

    import 'package:flutter/material.dart';
    import 'package:provider/provider.dart';
    import 'package:vrouter/vrouter.dart';
    
    void main() {
      runApp(BooksApp());
    }
    
    class Book {
      final String title;
      final Author author;
    
      Book(this.title, this.author);
    }
    
    class Author {
      String name;
    
      Author(this.name);
    }
    
    class AppState extends ChangeNotifier {
      bool _isAuthenticated = false;
    
      bool get isAuthenticated => _isAuthenticated;
    
      void authenticate() {
        if (isAuthenticated) return;
        _isAuthenticated = true;
        notifyListeners();
      }
    }
    
    class BooksApp extends StatelessWidget {
      final List<Book> books = [
        Book('Stranger in a Strange Land', Author('Robert A. Heinlein')),
        Book('Foundation', Author('Isaac Asimov')),
        Book('Fahrenheit 451', Author('Ray Bradbury')),
      ];
    
      @override
      Widget build(BuildContext context) {
        return ChangeNotifierProvider(
          create: (_) => AppState(),
          child: Builder(
            builder: (BuildContext context) {
              return VRouter(
                routes: [
                  VWidget(path: '/login', widget: AuthenticationScreen()),
                  VWidget(path: '/info', widget: InfoWidget()),
                  VGuard(
                    beforeEnter: (vRedirector) =>
                        authenticationCheck(context, vRedirector: vRedirector),
                    stackedRoutes: [
                      VWidget(
                        path: '/',
                        widget: BooksListScreen(books: books),
                        stackedRoutes: [
                          VWidget(
                            path: r'book/:bookId(\d+)',
                            widget: Builder(builder: (BuildContext context) {
                              return BookDetailsScreen(
                                book: books[int.parse(context.vRouter.pathParameters['bookId']!)],
                              );
                            }),
                          ),
                        ],
                      ),
                      VWidget(
                        path: '/authors',
                        widget: AuthorsListScreen(authors: books.map((e) => e.author).toList()),
                        stackedRoutes: [
                          VWidget(
                            path: r'/author/:authorId(\d+)',
                            widget: Builder(builder: (BuildContext context) {
                              return AuthorDetailsScreen(
                                author: books[int.parse(context.vRouter.pathParameters['authorId']!)]
                                    .author,
                              );
                            }),
                          ),
                        ],
                      ),
                    ],
                  ),
                ],
              );
            },
          ),
        );
      }
    
      Future<void> authenticationCheck(BuildContext context, {required VRedirector vRedirector}) async {
        if (!Provider.of<AppState>(context, listen: false).isAuthenticated) {
          vRedirector.to('/login', queryParameters: {'redirectedFrom': '${vRedirector.toUrl}'});
        }
      }
    }
    
    class AuthenticationScreen extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Center(
          child: ElevatedButton(
            onPressed: () {
              Provider.of<AppState>(context, listen: false).authenticate();
              context.vRouter.to(context.vRouter.queryParameters['redirectedFrom'] == null
                  ? '/'
                  : context.vRouter.queryParameters['redirectedFrom']!);
            },
            child: Text('Click to login'),
          ),
        );
      }
    }
    
    class InfoWidget extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Center(
          child: Text('Some info but actually there is nothing'),
        );
      }
    }
    
    
    class BooksListScreen extends StatelessWidget {
      final List<Book> books;
    
      BooksListScreen({required this.books});
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(),
          body: ListView(
            children: [
              for (var book in books)
                ListTile(
                  title: Text(book.title),
                  subtitle: Text(book.author.name),
                  onTap: () => context.vRouter.to('/book/${books.indexOf(book)}'),
                )
            ],
          ),
        );
      }
    }
    
    class AuthorsListScreen extends StatelessWidget {
      final List<Author> authors;
    
      AuthorsListScreen({required this.authors});
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(),
          body: ListView(
            children: [
              ElevatedButton(
                onPressed: () => context.vRouter.to('/'),
                child: Text('Go to Books Screen'),
              ),
              for (var author in authors)
                ListTile(
                  title: Text(author.name),
                  onTap: () => context.vRouter.to('/author/${authors.indexOf(author)}'),
                )
            ],
          ),
        );
      }
    }
    
    class BookDetailsScreen extends StatelessWidget {
      final Book book;
    
      BookDetailsScreen({required this.book});
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(),
          body: Padding(
            padding: const EdgeInsets.all(8.0),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(book.title, style: Theme.of(context).textTheme.headline6),
                ElevatedButton(
                  onPressed: () {
                    context.vRouter.to('/author/${context.vRouter.pathParameters['bookId']}');
                  },
                  child: Text(book.author.name),
                ),
              ],
            ),
          ),
        );
      }
    }
    
    class AuthorDetailsScreen extends StatelessWidget {
      final Author author;
    
      AuthorDetailsScreen({required this.author});
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(),
          body: Padding(
            padding: const EdgeInsets.all(8.0),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(author.name, style: Theme.of(context).textTheme.headline6),
              ],
            ),
          ),
        );
      }
    }
    

    诀窍是使用VGuard,在输入stackedRoutes 之前,检查用户是否经过身份验证。

    我使用queryParameters 来存储用户重定向的位置,但是如果您不希望用户重定向的位置出现在 url 中,您可以使用 historyState。话虽如此,在这种情况下我仍然更喜欢queryParameters,因为它允许链接共享。

    【讨论】:

      【解决方案2】:

      您可以使用qlevar_router 来执行此操作。 从示例中,在链接中,您可以使用 redirectGuard 定义一个 Middleware 来检查用户是否可以访问此页面或其子页面,否则只需提供重定向到的路由. 您也可以在 example 项目中看到这一点。 如果您授予访问Child 4 的权限,它将转到Child 4,否则您将被导航到Child 2。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-02-20
        • 2019-02-03
        • 1970-01-01
        • 1970-01-01
        • 2022-09-23
        • 2017-10-25
        • 2021-01-27
        • 1970-01-01
        相关资源
        最近更新 更多