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
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
}
},
),
),
);
}
}