How to implement user authentication in a Flutter app using shared_preferences and HTTP?

This Flutter code defines a login page that makes use of the shared_preferences and http packages to manage user authentication. The user enters their email and password, which are then sent to the specified API using an HTTP post request. If the login is successful, the API sends back a response containing an authentication token. This token is stored in the app's SharedPreferences so that the user doesn't have to log in again when the app is reopened.

The page is defined as a stateful widget with a boolean _isLoading flag, which is used to show a loading indicator while waiting for the API response. The page includes two TextFormField widgets for the email and password input fields, and an ElevatedButton for the sign-in action. The onPressed function of the sign-in button checks that the email and password fields are not empty and then calls the signIn function to make the API call.

The signIn function uses the http package to make an HTTP POST request to the specified API endpoint, passing in the user's email and password. If the response from the server is successful, the response body is parsed as a JSON object, and the authentication token is stored in the app's SharedPreferences. The Navigator then pushes a new page onto the stack, removing the login page so that the user can continue using the app. If the response is unsuccessful, the _isLoading flag is set to false, and an error message is printed to the console.

Overall, this code provides a simple example of implementing user authentication in a Flutter app using shared_preferences and HTTP.



Here's an example of a login page in Flutter using Shared Preferences and HTTP package:

You can test this Login page with this Username and Password:

    Username: eve.holt@reqres.in

    Password: cityslicka

Add dependencies to pubspec.yaml:

dependencies:
  flutter:
    sdk: flutter
  http: ^0.13.4
  shared_preferences: ^2.0.8

Create a new Dart file login_page.dart.

Here's what this code does:

  • The LoginPage widget is defined as a StatefulWidget.
  • A boolean variable _isLoading is created and initialized to false. This variable is used to show a loading spinner when the user clicks the sign-in button.
  • Two TextEditingController variables emailController and passwordController are created to handle user input for email and password.
  • In the build method, the system status bar color is set to transparent, and a Scaffold widget is returned, which contains a Container widget with a background gradient.
  • If _isLoading is true, a CircularProgressIndicator is shown. Otherwise, a column of widgets is displayed, including a title, two text fields for email and password, and a sign-in button.
  • When the sign-in button is pressed, it calls the signIn method.
  • In the signIn method, an instance of SharedPreferences is created to store the user's authentication token. Then, a Map object is created with email and password data. A http post request is sent to a URL endpoint with the data.
  • If the request is successful (statusCode 200), the response is decoded from JSON format and the authentication token is stored in SharedPreferences. Then, the user is directed to the MainPage screen using Navigator.of(context).pushAndRemoveUntil().
  • If the request is not successful, the _isLoading variable is set to false, and the response body is printed to the console for debugging purposes.

import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:http/http.dart' as http;

import 'package:shared_preferences/shared_preferences.dart';

import 'main.dart';

class LoginPage extends StatefulWidget {
  @override
  // ignore: library_private_types_in_public_api
  _LoginPageState createState() => _LoginPageState();
}

class _LoginPageState extends State<LoginPage> {
  bool _isLoading = false;
  final TextEditingController emailController = new TextEditingController();
  final TextEditingController passwordController = new TextEditingController();

  @override
  Widget build(BuildContext context) {
    SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.light
        .copyWith(statusBarColor: Colors.transparent));
    return Scaffold(
      body: Container(
        decoration: const BoxDecoration(
          gradient: LinearGradient(
              colors: [Colors.orange, Colors.orangeAccent],
              begin: Alignment.topCenter,
              end: Alignment.bottomCenter),
        ),
        child: _isLoading
            ? const Center(child: CircularProgressIndicator())
            : Column(
                children: [
                  Container(
                    margin: const EdgeInsets.only(top: 50.0),
                    padding: const EdgeInsets.symmetric(
                        horizontal: 20.0, vertical: 30.0),
                    child: const Text("Login",
                        style: TextStyle(
                            color: Colors.black,
                            fontSize: 40.0,
                            fontWeight: FontWeight.bold)),
                  ),
                  Container(
                    padding: const EdgeInsets.symmetric(
                        horizontal: 15.0, vertical: 20.0),
                    child: Column(
                      children: <Widget>[
                        TextFormField(
                          controller: emailController,
                          cursorColor: Colors.white,
                          style: const TextStyle(color: Colors.black),
                          decoration: const InputDecoration(
                            icon: Icon(Icons.email, color: Colors.black),
                            hintText: "Email",
                            border: UnderlineInputBorder(
                                borderSide: BorderSide(color: Colors.black)),
                            hintStyle: TextStyle(color: Colors.black),
                          ),
                        ),
                        const SizedBox(height: 30.0),
                        TextFormField(
                          controller: passwordController,
                          cursorColor: Colors.white,
                          obscureText: true,
                          style: const TextStyle(color: Colors.black),
                          decoration: const InputDecoration(
                            icon: Icon(Icons.lock, color: Colors.black),
                            hintText: "Password",
                            border: UnderlineInputBorder(
                                borderSide: BorderSide(color: Colors.black)),
                            hintStyle: TextStyle(color: Colors.black),
                          ),
                        ),
                      ],
                    ),
                  ),
                  Container(
                    width: MediaQuery.of(context).size.width,
                    height: 40.0,
                    padding: const EdgeInsets.symmetric(horizontal: 15.0),
                    margin: const EdgeInsets.only(top: 15.0),
                    child: ElevatedButton(
                      onPressed: emailController.text == "" ||
                              passwordController.text == ""
                          ? null
                          : () {
                              setState(() {
                                _isLoading = true;
                              });
                              signIn(emailController.text,
                                  passwordController.text);
                            },
                      child: const Text("Sign In",
                          style: TextStyle(color: Colors.black)),
                    ),
                  ),
                ],
              ),
      ),
    );
  }

  signIn(String email, pass) async {
    SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
    Map data = {'email': email, 'password': pass};
    var jsonResponse = null;
    var response =
        await http.post(Uri.parse('https://reqres.in/api/login'), body: data);
    if (response.statusCode == 200) {
      jsonResponse = json.decode(response.body);
      if (jsonResponse != null) {
        setState(() {
          _isLoading = false;
        });
        sharedPreferences.setString("token", jsonResponse['token']);
        // ignore: use_build_context_synchronously
        Navigator.of(context).pushAndRemoveUntil(
            MaterialPageRoute(
                builder: (BuildContext context) => const MainPage()),
            (Route<dynamic> route) => false);
      }
    } else {
      setState(() {
        _isLoading = false;
      });
      print(response.body);
    }
  }
}


Paste this code into the main file

import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';

import 'login.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "Login Page",
      debugShowCheckedModeBanner: false,
      home: const MainPage(),
      theme: ThemeData(primaryColor: Colors.orange),
    );
  }
}

class MainPage extends StatefulWidget {
  const MainPage({super.key});

  @override
  // ignore: library_private_types_in_public_api
  _MainPageState createState() => _MainPageState();
}

class _MainPageState extends State<MainPage> {
  late SharedPreferences sharedPreferences;

  @override
  void initState() {
    super.initState();
    checkLoginStatus();
  }

  checkLoginStatus() async {
    sharedPreferences = await SharedPreferences.getInstance();
    if (sharedPreferences.getString("token") == null) {
      // ignore: use_build_context_synchronously
      Navigator.of(context).pushAndRemoveUntil(
          MaterialPageRoute(builder: (BuildContext context) => LoginPage()),
          (Route<dynamic> route) => false);
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title:
            const Text("Login Screen", style: TextStyle(color: Colors.white)),
        actions: <Widget>[
          ElevatedButton(
            onPressed: () {
              sharedPreferences.clear();
              // ignore: deprecated_member_use
              sharedPreferences.commit();
              Navigator.of(context).pushAndRemoveUntil(
                  MaterialPageRoute(
                      builder: (BuildContext context) => LoginPage()),
                  (Route<dynamic> route) => false);
            },
            child: const Text("Log Out", style: TextStyle(color: Colors.white)),
          ),
        ],
      ),
      body: const Center(child: Text("Main Page")),
      drawer: const Drawer(),
    );
  }
}


GitHub Links

Follow @PradeepTheDeveloper Star Issue Sponsor


Comments

Popular posts from this blog

Error Handling in Flutter - Gradle issue

How to Make a Dynamic and Trending ListView with Flutter Widgets?

Understanding API integration with Getx State management