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)
如果用户直接打开这个URL,我想让用户先登录,那时路由会重定向到.
/authentication
登录后,我希望用户浏览以前打开的URL(如果有其他主页的话(
似乎这种事情可能会有所帮助,有什么想法吗?我们如何才能实现类似的事情?https://stackoverflow.com/a/43171515/2145844
我已经尝试了一些导航2.0/路由器API的示例,是的,我可以理解一些概念。。
我看过一些参考资料。
https://medium.com/flutter/learning-flutters-new-navigation-and-routing-system-7c9068155adehttps://github.com/orestesgaolin/navigator_20_examplehttps://github.com/flutter/flutter/tree/master/dev/benchmarks/test_apps/stocks
以下是如何使用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
,因为它允许链接共享。
您可以使用qlevar_router来完成此操作。在该示例中,在链接中,您可以使用redirectGuard定义中间件,以检查用户是否可以访问此页面或其子页面,否则只需提供重定向到的路由。您也可以在示例项目中看到这一点。如果您授予访问Child 4
的权限,它将转到Child 4
,否则您将被导航到Child 2
。