The following StackOverflowError was thrown building Consumer in Login through RestApi
501
The Error is due to getter method of the Auth. Where i returning the getter token
but i have to return _token
string which i am getting after logging in.Due to Name Confusion i am returning getter over and over again.
Author by
Shahryar Rafique
Updated on December 24, 2022Comments
-
Shahryar Rafique over 1 year
I am building simple authentication using Rest Api. Function are working but when I got token I want to move on mainPage of the Application. For this I used Consumer to build the Main Page using the bool value which I am getting from
_auth.token
when the token is present but it is returning Stack Overflow Error.The following StackOverflowError was thrown building Consumer<Auth>(dirty, dependencies: [_InheritedProviderScope<Auth>]): Stack Overflow The relevant error-causing widget was: Consumer<Auth>
My Code is main.dart
import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:provider/provider.dart'; import 'package:sole_entrepreneur/screens/business_overview_screen.dart'; import 'package:sole_entrepreneur/screens/splash_screen.dart'; // import './screens/selection_screen.dart'; import './screens/login_screen.dart'; import './screens/register_screen.dart'; import './screens/selection_screen.dart'; import './providers/auth.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); // await Auth().signIn('[email protected]', 'Developer'); // await Auth().register( // '[email protected]', "csdwx9spq", "matshary", "test", "testlast"); runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MultiProvider( providers: [ ChangeNotifierProvider( create: (ctx) => Auth(), ), ], child: Consumer<Auth>(builder: (ctx, auth, _) { // print(auth.isAuth); return MaterialApp( title: 'Flutter Demo', theme: ThemeData( scaffoldBackgroundColor: Colors.white, primaryColor: Color.fromRGBO(124, 116, 146, 1), buttonTheme: ButtonThemeData(textTheme: ButtonTextTheme.primary), appBarTheme: AppBarTheme( color: Colors.white, elevation: 0.0, iconTheme: IconThemeData(color: Colors.black)), ), home: auth.isAuth ? BusinessOverViewScreen() : FutureBuilder( builder: (context, authResultSnapshot) { print(auth.isAuth); return authResultSnapshot.connectionState == ConnectionState.waiting ? SplashScreen() : LoginScreen(); }, future: auth.tryAutoLogin(), ), routes: { LoginScreen.routeName: (ctx) => LoginScreen(), RegisterScreen.routeName: (ctx) => RegisterScreen(), BusinessOverViewScreen.routeName: (ctx) => BusinessOverViewScreen() }, ); })); } }
auth.dart
import 'dart:convert'; import 'dart:async'; import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:http/http.dart' as http; import 'package:shared_preferences/shared_preferences.dart'; class Auth with ChangeNotifier { String _token; DateTime _expiryDate; int _userId; Timer _authTimer; List<dynamic> _userRole; String _userEmail; String _userNiceName; String _userDisplayName; String _userAvatar; String message; bool get isAuth { return token != null; } String get token { print(_expiryDate); // print(_expiryDate.isAfter(DateTime.now()).toString()); if (_expiryDate != null && _expiryDate.isAfter(DateTime.now()) && _token != null) { return token; } return null; } int get userId { return _userId; } Future<void> authethicate( String email, String password, ) async { try { final url = 'https://soleentrepreneur.co.uk/wp-json/jwt-auth/v1/token'; final response = await http.post( url, body: { 'username': email, 'password': password, }, ); print( json.decode(response.body), ); final responseData = json.decode(response.body); if (responseData['message'] != null) { throw HttpException(responseData['message']); } _token = responseData['token']; _userEmail = responseData['user_email']; _userNiceName = responseData['user_nicename']; _userDisplayName = responseData['user_display_name']; _userRole = responseData['user_role']; _userId = responseData['user_id']; _userAvatar = responseData['avatar']; _expiryDate = DateTime.now().add(new Duration(days: 7)); notifyListeners(); SharedPreferences pref = await SharedPreferences.getInstance(); final userData = json.encode({ 'token': _token, 'userId': _userId, 'expiryDate': _expiryDate.toIso8601String(), 'userEmail': _userEmail, 'userNiceName': _userNiceName, 'userDisplayName': _userDisplayName, 'userRole': _userRole, 'userAvatar': _userAvatar, }); pref.setString('userData', userData); } catch (error) { throw (error); } } Future<void> signIn(String email, String password) async { await authethicate(email, password); } Future<void> register(String email, String password, String username, String firstName, String lastName) async { await registerAuth(email, username, password, firstName, lastName); } Future<void> registerAuth(String email, String username, String password, String firstName, String lastName) async { try { final registerUrl = 'https://soleentrepreneur.co.uk/wp-json/wp/v2/users/register'; final response = await http.post(registerUrl, headers: {'Content-Type': 'application/json'}, body: json.encode( { 'username': username, 'password': password, 'email': email, 'first_name': firstName, 'last_name': lastName }, )); final responseData = json.decode(response.body); if (responseData['code'] != 200) { throw HttpException(responseData['message']); } print( json.decode(response.body), ); message = responseData['message']; notifyListeners(); } catch (error) { throw error; } } Future<void> logOut() async { _userId = null; _token = null; _expiryDate = null; if (_authTimer != null) { _authTimer.cancel(); _authTimer = null; } notifyListeners(); final prefs = await SharedPreferences.getInstance(); prefs.clear(); } Future<void> tryAutoLogin() async { final prefs = await SharedPreferences.getInstance(); if (!prefs.containsKey('userData')) { print(_token); return false; } final extractedUserData = json.decode(prefs.getString('userData')) as Map<String, Object>; final expiryDate = DateTime.parse(extractedUserData['expiryDate']); if (expiryDate.isBefore(DateTime.now())) { print(_token); return false; } _token = extractedUserData['token']; _userId = extractedUserData['userId']; _expiryDate = expiryDate; _userEmail = extractedUserData['user_email']; _userDisplayName = extractedUserData['user_display_name']; _userNiceName = extractedUserData['user_nicename']; _userRole = extractedUserData['user_role']; _userAvatar = extractedUserData['avatar']; notifyListeners(); _autoLogOut(); print(_token); return true; } void _autoLogOut() { if (_authTimer != null) { _authTimer.cancel(); } final timeToExpiry = _expiryDate.difference(DateTime.now()).inSeconds; _authTimer = Timer(Duration(seconds: timeToExpiry), logOut); } }
login.dart
import 'dart:io'; import 'package:flutter/material.dart'; import '../providers/auth.dart'; import '../widgets/button.dart'; import '../widgets/text_form_field_style.dart'; import 'package:provider/provider.dart'; import '../models/httpException.dart'; class LoginScreen extends StatefulWidget { static const routeName = '/login'; @override _LoginScreenState createState() => _LoginScreenState(); } class _LoginScreenState extends State<LoginScreen> { final GlobalKey<FormState> _formKey = GlobalKey(); Map<String, String> _authData = { 'email': '', 'password': '', }; var _isLoading = false; void _showErrorDialog(String message) { showDialog( context: context, builder: (context) { return AlertDialog( content: Text(message), title: Text('An Error Occured'), actions: [ FlatButton( onPressed: () => Navigator.of(context).pop(), child: Text('Okay')) ], ); }, ); } Future<void> _submit() async { if (!_formKey.currentState.validate()) { print('not Returning'); return; } _formKey.currentState.save(); setState(() { _isLoading = true; }); try { await Provider.of<Auth>(context, listen: false) .signIn(_authData['email'], _authData['password']); } on HttpException catch (error) { var errormessage = 'Authethication failed'; if (error.toString().contains('Unknown email address.')) { errormessage = 'Unknown email address. Check again or try your username'; } else if (error.toString().contains('[jwt_auth] incorrect_password')) { errormessage = 'The password you entered for the email address is incorrect.'; } else if (error.toString().contains('[jwt_auth] invalid_username')) { errormessage = 'This email is not valid'; } _showErrorDialog(errormessage); } catch (error) { var errormessage = 'Could not authenticate you. Please try again later'; print(error); _showErrorDialog(errormessage); } setState(() { _isLoading = false; }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(), body: SafeArea( child: Column( children: [ Expanded( child: Container( margin: EdgeInsets.all(MediaQuery.of(context).size.width / 5), child: Image.asset('assets/Logo.png'), color: Colors.blue, ), ), Expanded( child: Form( key: _formKey, child: SingleChildScrollView( child: Column( children: [ buildTextFormStyle( MediaQuery.of(context).size.height / 9, TextFormField( decoration: InputDecoration( labelText: 'Email', border: InputBorder.none, contentPadding: EdgeInsets.all(5), ), keyboardType: TextInputType.emailAddress, // ignore: missing_return validator: (value) { if (value.isEmpty || !value.contains('@')) return 'Invalid email!'; }, onSaved: (newValue) { _authData['email'] = newValue; }, ), ), SizedBox(height: 10), buildTextFormStyle( MediaQuery.of(context).size.height / 9, TextFormField( decoration: InputDecoration( labelText: 'Password', border: InputBorder.none, contentPadding: EdgeInsets.all(5), ), obscureText: true, // ignore: missing_return validator: (value) { if (value.isEmpty || value.length < 5) return 'Password is too short!'; }, onSaved: (newValue) { _authData['password'] = newValue; }, ), ), if (_isLoading) CircularProgressIndicator() else AppButton(name: 'LOGIN', onPressed: _submit), ], ), ), ), ), ], ), ), ); } } //Text Field Style
-
Abhishek Ghaskata over 3 yearsyou don't need MultiProvider.
-
Shahryar Rafique over 3 yearsI need multiProvider later the error in my point of view is causing because of something wrong in auth file but i could not found anything.
-
Abhishek Ghaskata over 3 yearscan you please try flutter clean ? and rerun again
-
Abhishek Ghaskata over 3 yearsuse
class Auth extends ChangeNotifier
in auth.dart. becauseChangeNotifier
is class not mixin @ShahryarRafique -
Shahryar Rafique over 3 yearsLet us continue this discussion in chat.
-
Shahryar Rafique over 3 yearsas i remove
if (_expiryDate != null && _expiryDate.isAfter(DateTime.now()) && _token != null) { return token; }
the error is resolved but a continuous loop start and only SplashScrren is showing.