Ví dụ đăng nhập và đăng xuất với Flutter Getx
Trong bài viết này chúng ta sẽ xem xét một ví dụ đăng nhập và đăng xuất với Flutter Getx.
- Tạo một Form đăng nhập.
- Sử dụng Middleware để kiểm tra và chuyển hướng người dùng tới trang đăng nhập nếu người dùng đang cố gắng truy cập vào một trang nào đó trong tình trạng chưa đăng nhập.
Các bài viết và ví dụ có liên quan tới GetX Middleware:
1. Cài đặt thư viện
pubspec.yaml
dependencies:
get: ^5.0.0-release-candidate-9
shared_preferences: ^2.3.2
Chú ý: Thư viện shared_preferences được sử dụng để lưu trữ thông tin người dùng trên thiết bị sau khi người dùng đăng nhập thành công. Thông tin này là cơ sở để biết người dùng đã đăng nhập hay chưa.
2. MainApp
main.dart
import 'package:flutter/material.dart';
import 'user_controller.dart';
import 'package:get/get.dart';
import 'auth_middleware.dart';
import 'dashboard_screen.dart';
import 'login_screen.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return GetMaterialApp(
title: 'Flutter GetX Login Demo',
debugShowCheckedModeBanner: false,
initialRoute: DashboardScreen.routeName,
getPages: [
GetPage(
name: LoginScreen.routeName,
page: () => const LoginScreen(),
),
GetPage(
name: DashboardScreen.routeName,
page: () => const DashboardScreen(),
middlewares: [
AuthMiddleware(), // IMPORTANT!!
],
),
],
binds: [
// Make sure UserController is available for all Pages.
Bind.lazyPut(() => UserController(), fenix: true),
],
);
}
}
3. Model
model.dart
import 'dart:convert';
import 'package:shared_preferences/shared_preferences.dart';
class User {
static const String _key_ = "__userInfo__";
String userName;
String fullName;
String role;
User({
required this.userName,
required this.fullName,
required this.role,
});
String toJson() {
return jsonEncode({
"userName": userName,
"fullName": fullName,
"role": role,
});
}
void saveToSharedPreferences(SharedPreferences sp) {
print("--> saveToSharedPreferences");
String json = toJson();
sp.setString(_key_, json);
}
void removeFromSharedPreferences(SharedPreferences sp) {
print("--> removeToSharedPreferences");
sp.remove(_key_);
}
static User fromJson(String json) {
Map<String, dynamic> map = jsonDecode(json);
return fromMap(map);
}
static User fromMap(Map<String, dynamic> map) {
return User(
userName: map['userName'],
fullName: map['fullName'],
role: map['role'],
);
}
static User? fromSharedPreferences(SharedPreferences sp) {
print("--> fromSharedPreferences");
String? json = sp.getString(_key_);
if (json == null) {
return null;
}
return fromJson(json);
}
}
user_controller.dart
import 'package:get/get.dart';
import 'model.dart';
class UserController extends GetxController {
// Logged-In user
User? user;
}
4. Login
Người dùng nhận được một thông báo lỗi khi nhập sai tên đăng nhập hoặc mật khẩu:
Khi đăng nhập thành công, người dùng sẽ được chuyển tới DashboardScreen.
login_screen.dart
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'dashboard_screen.dart';
import 'login_controller.dart';
class LoginScreen extends StatelessWidget {
static const String routeName = "/login";
const LoginScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Login"),
backgroundColor: Colors.blue,
),
body: GetBuilder(
init: Get.put(LoginController()),
builder: (LoginController controller) {
return Padding(
padding: const EdgeInsets.all(10),
child: Column(
children: [
TextField(
controller: controller.userNameController,
decoration: const InputDecoration(
label: Text('User Name'),
border: OutlineInputBorder(),
),
),
const SizedBox(height: 10),
TextField(
controller: controller.passwordController,
obscureText: true,
decoration: const InputDecoration(
label: Text('Password'),
border: OutlineInputBorder(),
),
),
const SizedBox(height: 10),
const Text("Test with user/pass: tom/123"),
const SizedBox(height: 10),
ElevatedButton(
onPressed: () {
controller.doLogin();
},
child: const Text("Login"),
),
const SizedBox(height: 10),
ElevatedButton(
onPressed: () {
Get.toNamed(DashboardScreen.routeName);
},
child: const Text("Go to Dashboard Screen"),
),
],
),
);
},
),
);
}
}
login_controller.dart
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'dashboard_screen.dart';
import 'model.dart';
import 'user_provider.dart';
class LoginController extends GetxController {
final UserProvider userProvider = Get.put(UserProvider());
final TextEditingController userNameController = TextEditingController();
final TextEditingController passwordController = TextEditingController();
Future<void> doLogin() async {
String userName = userNameController.text;
String password = passwordController.text;
try {
User? user = await userProvider.doLogin(userName, password);
SharedPreferences sp = await SharedPreferences.getInstance();
user!.saveToSharedPreferences(sp);
Get.toNamed(DashboardScreen.routeName);
} catch (e, stacktrace) {
// print(stacktrace);
Get.showSnackbar(
GetSnackBar(
message: "Error: $e",
duration: const Duration(seconds: 5),
),
);
}
}
@override
void dispose() {
userNameController.dispose();
passwordController.dispose();
super.dispose();
}
}
UserProvider là một lớp "Provider". Provider thực hiện các hoạt động CRUD (Create, Read, Update, Delete), nó gửi các yêu cầu GET, POST, PUT và DELETE tới máy chủ REST.
user_provider.dart
import 'model.dart';
class UserProvider {
Future<User?> doLogin(String userName, String password) async {
// Send POST request to server...
if (userName == 'tom' && password == '123') {
return User(
userName: 'tom',
fullName: 'Tom Cat',
role: 'ADMIN',
);
}
throw "Invalid userName or password";
}
}
5. Dashboard
DashboardScreen hiển thị thông tin người dùng khi người dùng đã đăng nhập thành công.
dashboard_screen.dart
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'logout_controller.dart';
import 'user_controller.dart';
class DashboardScreen extends StatelessWidget {
static const String routeName = "/dashboard";
const DashboardScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Dashboard"),
backgroundColor: Colors.blue,
),
body: GetBuilder(
builder: (UserController controller) {
return Center(
child: Column(
children: [
Text("Hello: ${controller.user!.userName}"),
Text("Full Name: ${controller.user!.fullName}"),
Text("Role: ${controller.user!.role}"),
const SizedBox(height: 10),
TextButton(
onPressed: _doLogout,
child: const Text("Logout"),
),
],
),
);
},
),
);
}
void _doLogout() {
LogoutController logoutController = Get.put(LogoutController());
logoutController.doLogout();
}
}
6. AuthMiddleware
Middleware là một thực thể logic nằm giữa người dùng và trang mục tiêu mà người dùng mong muốn. Code của Middleware sẽ được thực thi trước khi yêu cầu của người dùng được gửi tới trang mục tiêu. Bạn có thể sử dụng Middleware để chuyển hướng người dùng tới một trang khác tuỳ thuộc vào các điều kiện được xác định trong Middleware.
main.dart (**)
GetMaterialApp(
...
getPages: [
...
GetPage(
name: DashboardScreen.routeName,
page: () => const DashboardScreen(),
middlewares: [
AuthMiddleware(), // IMPORTANT!!
],
),
],
...
)
Trong ví dụ này người dùng cố gắng truy cập vào DashboardScreen. AuthMiddleware sẽ kiểm tra xem người dùng đã đăng nhập chưa, nếu chưa yêu cầu sẽ được chuyển hướng tới LoginScreen.
Chú ý: Khi người dùng đã đăng nhập thành công, thông tin người dùng sẽ được lưu vào SharedPreferences. AuthMiddleware dựa vào điều này để kiểm tra xem người dùng đã đăng nhập hay chưa.
auth_middleware.dart
import 'dart:async';
import 'package:get/get.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'login_screen.dart';
import 'model.dart';
import 'user_controller.dart';
class AuthMiddleware extends GetMiddleware {
@override
FutureOr<RouteDecoder?> redirectDelegate(RouteDecoder route) async {
SharedPreferences sp = await SharedPreferences.getInstance();
try {
User? user = User.fromSharedPreferences(sp);
if (user == null) {
print(" Not logged in --> redirect to login page");
return RouteDecoder.fromRoute(LoginScreen.routeName);
}
// UserController was created in GetMaterialApp (** @see: main.dart)
UserController userController = Get.find();
userController.user = user!;
} catch (e, stacktrace) {
print(stacktrace);
print(" Error: --> redirect to login page");
return RouteDecoder.fromRoute(LoginScreen.routeName);
}
return super.redirectDelegate(route);
}
}
Xem thêm bài viết chuyên sâu về Getx Middleware:
- Hướng dẫn và ví dụ Flutter Getx middleware
7. Logout
void _doLogout() {
LogoutController logoutController = Get.put(LogoutController());
logoutController.doLogout();
}
logout_controller.dart
import 'package:get/get.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'login_screen.dart';
import 'model.dart';
import 'user_controller.dart';
class LogoutController extends GetxController {
Future<void> doLogout() async {
UserController? userController = Get.findOrNull();
userController?.user = null;
//
SharedPreferences sp = await SharedPreferences.getInstance();
User? user = User.fromSharedPreferences(sp);
user?.removeFromSharedPreferences(sp);
// Go to LoginScreen and remove route histories.
Get.offNamed(LoginScreen.routeName);
}
}
Các hướng dẫn lập trình Flutter
- Hướng dẫn và ví dụ Flutter Column
- Hướng dẫn và ví dụ Flutter Stack
- Hướng dẫn và ví dụ Flutter IndexedStack
- Hướng dẫn và ví dụ Flutter Spacer
- Hướng dẫn và ví dụ Flutter Expanded
- Hướng dẫn và ví dụ Flutter SizedBox
- Hướng dẫn và ví dụ Flutter Tween
- Cài đặt Flutter SDK trên Windows
- Cài đặt Flutter Plugin cho Android Studio
- Tạo ứng dụng Flutter đầu tiên của bạn - Hello Flutter
- Hướng dẫn và ví dụ Flutter Scaffold
- Hướng dẫn và ví dụ Flutter AppBar
- Hướng dẫn và ví dụ Flutter BottomAppBar
- Hướng dẫn và ví dụ Flutter SliverAppBar
- Hướng dẫn và ví dụ Flutter TextButton
- Hướng dẫn và ví dụ Flutter ElevatedButton
- Hướng dẫn và ví dụ Flutter ShapeBorder
- Hướng dẫn và ví dụ Flutter EdgeInsetsGeometry
- Hướng dẫn và ví dụ Flutter EdgeInsets
- Hướng dẫn và ví dụ Flutter CircularProgressIndicator
- Hướng dẫn và ví dụ Flutter LinearProgressIndicator
- Hướng dẫn và ví dụ Flutter Center
- Hướng dẫn và ví dụ Flutter Align
- Hướng dẫn và ví dụ Flutter Row
- Hướng dẫn và ví dụ Flutter SplashScreen
- Hướng dẫn và ví dụ Flutter Alignment
- Hướng dẫn và ví dụ Flutter Positioned
- Hướng dẫn và ví dụ Flutter ListTile
- Hướng dẫn và ví dụ Flutter SimpleDialog
- Hướng dẫn và ví dụ Flutter AlertDialog
- Navigation và Routing trong Flutter
- Hướng dẫn và ví dụ Flutter Navigator
- Hướng dẫn và ví dụ Flutter TabBar
- Hướng dẫn và ví dụ Flutter Banner
- Hướng dẫn và ví dụ Flutter BottomNavigationBar
- Hướng dẫn và ví dụ Flutter FancyBottomNavigation
- Hướng dẫn và ví dụ Flutter Card
- Hướng dẫn và ví dụ Flutter Border
- Hướng dẫn và ví dụ Flutter ContinuousRectangleBorder
- Hướng dẫn và ví dụ Flutter RoundedRectangleBorder
- Hướng dẫn và ví dụ Flutter CircleBorder
- Hướng dẫn và ví dụ Flutter StadiumBorder
- Hướng dẫn và ví dụ Flutter Container
- Hướng dẫn và ví dụ Flutter RotatedBox
- Hướng dẫn và ví dụ Flutter CircleAvatar
- Hướng dẫn và ví dụ Flutter TextField
- Hướng dẫn và ví dụ Flutter IconButton
- Hướng dẫn và ví dụ Flutter FlatButton
- Hướng dẫn và ví dụ Flutter SnackBar
- Hướng dẫn và ví dụ Flutter Drawer
- Ví dụ Flutter Navigator pushNamedAndRemoveUntil
- Hiển thị hình ảnh trên Internet trong Flutter
- Hiển thị ảnh Asset trong Flutter
- Flutter TextInputType các kiểu bàn phím
- Hướng dẫn và ví dụ Flutter NumberTextInputFormatter
- Hướng dẫn và ví dụ Flutter Builder
- Làm sao xác định chiều rộng của Widget cha trong Flutter
- Bài thực hành Flutter thiết kế giao diện màn hình đăng nhập
- Bài thực hành Flutter thiết kế giao diện trang (1)
- Khuôn mẫu thiết kế Flutter với các lớp trừu tượng
- Bài thực hành Flutter thiết kế trang Profile với Stack
- Bài thực hành Flutter thiết kế trang profile (2)
- Hướng dẫn và ví dụ Flutter ListView
- Hướng dẫn và ví dụ Flutter GridView
- Bài thực hành Flutter với gói http và dart:convert (2)
- Bài thực hành Flutter với gói http và dart:convert (1)
- Ứng dụng Flutter Responsive với Menu Drawer
- Flutter GridView với SliverGridDelegate tuỳ biến
- Hướng dẫn và ví dụ Flutter image_picker
- Flutter upload ảnh sử dụng http và ImagePicker
- Hướng dẫn và ví dụ Flutter SharedPreferences
- Chỉ định cổng cố định cho Flutter Web trên Android Studio
- Tạo Module trong Flutter
- Hướng dẫn và ví dụ Flutter SkeletonLoader
- Hướng dẫn và ví dụ Flutter Slider
- Hướng dẫn và ví dụ Flutter Radio
- Bài thực hành Flutter SharedPreferences
- Hướng dẫn và ví dụ Flutter InkWell
- Hướng dẫn và ví dụ Flutter GetX GetBuilder
- Hướng dẫn và ví dụ Flutter GetX obs Obx
- Hướng dẫn và ví dụ Flutter flutter_form_builder
- Xử lý lỗi 404 trong Flutter GetX
- Ví dụ đăng nhập và đăng xuất với Flutter Getx
- Hướng dẫn và ví dụ Flutter multi_dropdown
Show More