flutterdartmobilebloc

How do I access the authentication token obtained on Login using BloC with Flutter


I have completed the following tutorial https://dev.to/amartyadev/flutter-app-authentication-with-django-backend-1-21cp which although useful, has left me still pretty clueless how to move forward. I am able to login and the user details are saved via a UserRepository class to a sqlite database locally, including the authentication token, but I have no idea how to access this when trying to make repeat requests to the server for data. there are no problems with the existing code but I will present several pages so you can see what I have done and am trying to achieve and how it is put together.

main.dart:

import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:bloc/bloc.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import './repository/user_repository.dart';

import './bloc/authentication/authentication_bloc.dart';
import './screens/splash_screen.dart';
import './screens/login/login_screen.dart';
import './screens/home_screen.dart';
import './widgets/loading_indicator.dart';
import './widgets/video_widget.dart';
import './screens/home_screen.dart';

const welcomeUrl = 'https://soundjudgement.github.io/static-sf/tour.mp4';
class SimpleBlocDelegate extends BlocDelegate {
  @override
  void onEvent(Bloc bloc, Object event) {
    super.onEvent(bloc, event);
    print(event);
  }

  @override
  void onTransition(Bloc bloc, Transition transition) {
    super.onTransition(bloc, transition);
    print(transition);
  }

  @override
  void onError(Bloc bloc, Object error, StackTrace stacktrace) {
    super.onError(bloc, error, stacktrace);
  }
}

void main() {
  BlocSupervisor.delegate = SimpleBlocDelegate();
  final userRepository = UserRepository();

  runApp(BlocProvider<AuthenticationBloc>(
    create: (context) {
      return AuthenticationBloc(userRepository: userRepository)
        ..add(AppStarted());
    },
    child: SundayFundayApp(userRepository: userRepository),
  ));
}

class SundayFundayApp extends StatelessWidget {
  // This widget is the root of your application.

  final UserRepository userRepository;

  SundayFundayApp({Key key, @required this.userRepository}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'The Yard Mobile App',
      theme: ThemeData(
        primarySwatch: Colors.yellow,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: BlocBuilder<AuthenticationBloc, AuthenticationState>(
        builder: (context, state) {
          if (state is AuthenticationUnintialized) {
            return SplashPage();
          }
          if (state is AuthenticationAuthenticated) {
            return HomeScreen();
          }
          if (state is AuthenticationUnauthenticated) {
            return LogInScreen(
              userRepository: userRepository,
            );
          }
          if (state is AuthenticationLoading) {
            return LoadingIndicator();
          }
        },
      ),
    );
  }
}

user_repository.dart

import 'dart:async';
import '../models/user_model.dart';
import 'package:meta/meta.dart';
import '../models/api_model.dart';
import '../api_connection/api_connection.dart';
import '../dba/user_dba.dart';

class UserRepository {
  final userDao = UserDba();

  Future<User> authenticate({
    @required String username,
    @required String password,
  }) async {
    UserLogin userLogin = UserLogin(username: username, password: password);
    Token token = await getToken(userLogin);
    User user = User(
      id: 0,
      username: username,
      token: token.token,
    );
    return user;
  }

  Future<void> persistToken({@required User user}) async {
    // write token with the user to the database
    await userDao.createUser(user);
  }

  Future<void> deleteToken({@required int id}) async {
    await userDao.deleteUser(id);
  }

  Future<bool> hasToken() async {
    bool result = await userDao.checkUser(0);
    return result;
  }
}

user_dao.dart:

import '../database/user_database.dart';
import '../models/user_model.dart';

class UserDao {
  final dbProvider = DatabaseProvider.dbProvider;

  Future<int> createUser(User user) async {
    final db = await dbProvider.database;

    var result = db.insert(userTable, user.toDatabaseJson());
    return result;
  }

  Future<int> deleteUser(int id) async {
    final db = await dbProvider.database;
    var result = await db
        .delete(userTable, where: "id = ?", whereArgs: [id]);
    return result;
  }

  Future<bool> checkUser(int id) async {
    final db = await dbProvider.database;
    try {
      List<Map> users = await db
          .query(userTable, where: 'id = ?', whereArgs: [id]);
      if (users.length > 0) {
        return true;
      } else {
        return false;
      }
    } catch (error) {
      return false;
    }
  }
}

login_screen.dart:

import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import '../../repository/user_repository.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../bloc/authentication/authentication_bloc.dart';
import './bloc/login_bloc.dart';
import 'login_form.dart';

class LogInScreen extends StatelessWidget {

  final UserRepository userRepository;

  LogInScreen({Key key, @required this.userRepository})
      : assert(userRepository != null),
        super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        // Here we take the value from the MyHomePage object that was created by
        // the App.build method, and use it to set our appbar title.
        title: Text('The Yard App'),
      ),
      body:  Container(
        decoration: BoxDecoration(
          image: DecorationImage(
            image: AssetImage('assets/images/theyardbook.png'),
              fit: BoxFit.cover,
          )
        ),
      child: BlocProvider(
          create: (context) {
            return LoginBloc(
              authenticationBloc: BlocProvider.of<AuthenticationBloc>(context),
              userRepository: userRepository,
            );
          },
        child: Container(
           child: Scaffold(
            backgroundColor: Colors.transparent,
            body: Container(
              width: MediaQuery.of(context).size.width,
              decoration: BoxDecoration(
                borderRadius: BorderRadius.circular(20),
                color: Colors.transparent,
              ),
              child: Padding(
                padding: EdgeInsets.all(23),
                child:     LoginForm(),

                ),
              ),
            ),
          ),
        ),
      ),
    );
  }
}

Once the user is logged in, the app takes you to a home screen and it is this screen I have placed a button to take me to another screen which will fetch data from the server to display. For now the only data available is the one single registered user which is fine, I just need to see how it works because I am totally stuck and have been for 3 days. What I need to know, is how do I access the authentication token?? I am assuming (hoping) the process will be the same accessing any data saved to a local db.

I can copy and paste more code but I feel like there is a lot there and the tutorial is pretty clear, it just help me with this final


Solution

  • So here is the code in the user-dao, which I just need to import in any widget/class I am needing to access the server. Seems obvious and totally straight forward but amongst all the Dart code which I am unfamiliar with and the many files used in the bloc pattern, I think my head was getting confused.

      Future<String> getUserToken(int id) async {
        final db = await dbProvider.database;
        try {
          var res = await db.rawQuery("SELECT token FROM userTable WHERE id=0");
          return res.isNotEmpty ? (User.fromDatabaseJson(res.first)).token : null;
        } catch (err) {
          return null;
        }
      }
    
    

    Here is the new users_screen code, using FutureBuilder

    import 'package:flutter/material.dart';
    import 'package:flutter/widgets.dart';
    import 'package:flutter_bloc/flutter_bloc.dart';
    import '../widgets/logout_button.dart';
    import '../repository/user_repository.dart';
    import 'package:http/http.dart' as http;
    import '../dao/user_dao.dart';
    import '../api_connection/api_connection.dart';
    import '../models/user_model.dart';
    
    class UserScreen extends StatefulWidget {
    
      @override
      _UserScreenState createState() => _UserScreenState();
    }
    
    class _UserScreenState extends State<UserScreen> {
    
      Future<User> futureUser;
    
      @override
      void initState() {
        super.initState();
        futureUser = getUser();
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('The Yard Users'),
          ),
          body: Container(
            child: FutureBuilder( // use a future builder widget
              future: futureUser, // assign the future
              builder: (context, snapshot) {
                if (snapshot.hasData) {
                  return Column(
                    // show your layout if future is done
                    mainAxisAlignment: MainAxisAlignment.center,
                    crossAxisAlignment: CrossAxisAlignment.center,
                    children: <Widget>[
                      Padding(
                        padding: EdgeInsets.only(left: 30.0),
                        child: Text(
                          'Username: ${snapshot.data.username}', // get the username from the snapshot
                          style: TextStyle(
                            fontSize: 24.0,
                          ),
                        ),
                      ),
                      // Logout button
                      Padding(
                        padding: EdgeInsets.fromLTRB(34.0, 20.0, 0.0, 0.0),
                        child: Container(
                            width: MediaQuery.of(context).size.width * 0.85,
                            height: MediaQuery.of(context).size.width * 0.16,
                            child: LogoutButton()
                        ),
                      ),
                    ],
                  );
                } else {
                  return CircularProgressIndicator(); // show a progress indicator while future is executing
                }
              },
            ),
          ),
        );
      }
    }