Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to save user sign-in details in Flutter?

Tags:

flutter

dart

I am new to flutter and want to make an app which only authenticated users (via filling email and password) can use. So I am thinking of making a root widget called Authentication where I will check if the user is authenticated or not. If they are then take them to Home() Widget (which is basically app home page) else to SignIn() Widget (which is signin page) .

  • I have to check for user authentication in 2 senerios:
    • When app opens so that previously signed in user does not have to signin again
    • After filling up Email-Id and Password user clicks on Sign In button

I am facing the following problem and don't know how do I solve them ( Assume that there is no signup option and user data is entered to db directly not through some UI ):

  • If a user is already signed in how to take them directly to Home() Widget ?

    This is code of what I have currently I am not sure if is the right way of doing this type of app so if there is a better way to do this please tell :


    import 'package:flutter/material.dart';
    import 'package:myapp/home.dart';
    import 'package:myapp/signIn.dart';


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

    class Authenticate extends StatelessWidget {


      final String authenticateEmail;
      final String authenticatePassword;

      Authenticate({this.authenticateEmail, this.authenticatePassword}); 




      // Make a call to db to check if the data provided is correct or not 
      // If it is correct we then navigate the user to Home() Widget 
      // Else to SignIn() Widget

  @override
  Widget build(BuildContext context) {

     if ( make some call to db to check if data is there) {
       return Home();
     }
     else {
       return SignIn();
     }

  }
}

The issue with above code is when the app is opened for the first time how to take user directly to SignIn() Widget should I initilize the fields with empty string and in method check for condition if string is empty or not ?

like image 430
sid597 Avatar asked Feb 07 '20 11:02

sid597


3 Answers

Use user sessions instead. Check out FlutterSession. The package adds user session support in Flutter and is easy to use.

bool isAuth = Authenticate({this.authenticateEmail, this.authenticatePassword});

// Store value to session
await FlutterSession().set("isAuth", isAuth);

// Retrieve item from session
dynamic token = await FlutterSession().get("isAuth");
like image 67
Jhourlad Estrella Avatar answered Nov 15 '22 22:11

Jhourlad Estrella


Create a sqlite table and then when authenticating user is successful from server save required details to local table (delete any previous row saved before saving).

Now just check on app start that whether user table is empty or not and decide where the flow should be.

On first run table will be empty by default so it will show login page

APP RUN -> Check if row exists in user table

if YES ->  return Home();
else -> return SignIn();
like image 45
Dev Avatar answered Nov 15 '22 22:11

Dev


The root widget which you are calling Authentication is the app.

In pubspec.yaml add two dependencies

provider: ^4.0.3
shared_preferences: ^0.5.6+1

Similar to the example, I wrote on Flutter provider state management, logout concept.

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

// If successful, returns a token. Otherwise throws an error.
typedef Future<String> SignIn({
  @required final String username,
  @required final String password,
});

// If successful, returns void. Otherwise throws an error.
typedef Future<void> SignOut({
  @required final String token,
});

// ----------------------------------------------------------------------------

class Session with ChangeNotifier {
  String _token; // can be null
  final SignIn _signIn;
  final SignOut _signOut;

  Session({
    @required String token,
    @required SignIn signIn,
    @required SignOut signOut,
  })  : assert(signIn != null),
        assert(signOut != null),
        this._token = token,
        this._signIn = signIn,
        this._signOut = signOut;

  Future<void> signIn({
    @required final String username,
    @required final String password,
  }) async {
    assert(username != null);
    assert(password != null);

    final String token = await this._signIn(
      username: username,
      password: password,
    );
    this._token = token;
    this.notifyListeners();
  }

  Future<void> signOut() async {
    await this._signOut(token: this._token);
    this._token = null;
    this.notifyListeners();
  }

  bool get isAuthenticated {
    return (this._token != null);
  }
}

// ----------------------------------------------------------------------------

Future<void> main() async {
  // The app would load and present an error message on screen to add the following line.
  // https://github.com/flutter/flutter/issues/39620
  // https://api.flutter.dev/flutter/widgets/WidgetsFlutterBinding/ensureInitialized.html
  WidgetsFlutterBinding.ensureInitialized();

  // Initialize some local persistence.
  // Could be SQLite or somewhere encrypted.
  SharedPreferences prefs = await SharedPreferences.getInstance();

  final Session session = Session(
    token: prefs.getString('token'),
    signIn: ({
      @required final String username,
      @required final String password,
    }) async {
      assert(username != null);
      assert(password != null);

      // Contact the server to validate credentials and get token.
      await Future.delayed(Duration(milliseconds: 500)); // network delay
      if ((username != 'johnsmith') || (password != 'opensesame')) {
        throw new Exception("bad username or password");
      } else {
        final String token = '9djdhy89032jfdhdf70912';
        // Store the token locally.
        prefs.setString('token', token);
        return token;
      }
    },
    signOut: ({@required final String token}) async {
      assert(token != null);

      // Contact the server to sign out.
      await Future.delayed(Duration(milliseconds: 500)); // network delay
      // Update the local storage.
      prefs.setString('token', null);
    },
  );

  return runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider<Session>.value(value: session),
      ],
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(final BuildContext context) {
    return Consumer<Session>(
      builder: (final BuildContext context, final Session session, final Widget child) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(primarySwatch: Colors.blue),
          home: session.isAuthenticated ? MyHomePage() : MySignInPage(),
        );
      },
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(final BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("Home [Auth Protected]")),
      body: Center(
        child: RaisedButton(
          child: const Text("Sign Out"),
          onPressed: () {
            final Session session = Provider.of<Session>(context, listen: false);
            session.signOut();
          },
        ),
      ),
    );
  }
}

// Of course this would have username and password inputs and a submit button.
class MySignInPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("Sign In")),
      body: Center(
        child: RaisedButton(
          child: const Text("Sign In with johnsmith, opensesame"),
          onPressed: () {
            final Session session = Provider.of<Session>(context, listen: false);
            session.signIn(username: 'johnsmith', password: 'opensesame');
          },
        ),
      ),
    );
  }
}
like image 33
Ted Henry Avatar answered Nov 15 '22 22:11

Ted Henry



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!