Home > Blockchain >  Login with Facebook not working as expected - flutter
Login with Facebook not working as expected - flutter

Time:07-06

I'm trying to implement login with Facebook in my app which it's "working" but not necessarily as expected, I'll write down the issues I'm having.

  • When I try to login, I don't get redirected to the homepage and the logs show an error this error: W/Firestore(27484): (24.1.2) [Firestore]: Listen for Query(target=Query(users where [email protected] order by name);limitType=LIMIT_TO_FIRST) failed: Status{code=PERMISSION_DENIED, description=Missing or insufficient permissions., cause=null} E/flutter (27484): [ERROR:flutter/lib/ui/ui_dart_state.cc(198)] Unhandled Exception: [cloud_firestore/permission-denied] The caller does not have permission to execute the specified operation. I'm redirected to the login page again and the login only works in the second try.

  • When I sign out it looks like it works fine because I got redirected to the login page but the logs show the same error above.

  • For last some times it happens that if I exit the app(by pressing back button) and then re-open I get redirected to the home page instead of the login page it doesn't happen always so not sure what is causing that. I'm displaying the user data in the home page and in this case it's empty.

I was thinking that it could be related to my rules set in firebase but I'm not really sure , I would appreciate it very much if someone could guide me or point me what I'm missing or doing incorrectly.

Below my code:

main.dart

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const Wrapper(),
      routes: <String, WidgetBuilder>{
        '/home': (BuildContext context) => const HomePage(),
        '/login': (BuildContext context) => const LoginPage(),
      },
    );
  }
}

wrapper.dart

class Wrapper extends StatelessWidget {
  const Wrapper({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    //print(FirebaseAuth.instance.currentUser);
    if(FirebaseAuth.instance.currentUser?.email == null){
      return const LoginPage();
    }
    else{
      return const HomePage();
    }
  }
}

login_page.dart

class LoginPage extends StatefulWidget {
  const LoginPage({Key? key}) : super(key: key);

  String get title => 'login';

  @override
  State<LoginPage> createState() => _LoginPageState();
}

class _LoginPageState extends State<LoginPage> {
  String userEmail = "";
  UserModel? _currentUser;
  bool loading = false;
  @override
  Widget build(BuildContext context) {
    return WillPopScope(
      child: Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              const Padding(
                padding: EdgeInsets.symmetric(horizontal: 8.0, vertical: 10.0),
                child: TextField(
                  decoration: InputDecoration(
                    border: OutlineInputBorder(),
                    hintText: 'Email',
                  ),
                ),
              ),
              const Padding(
                  padding:
                      EdgeInsets.symmetric(horizontal: 8.0, vertical: 10.0),
                  child: TextField(
                    decoration: InputDecoration(
                      border: OutlineInputBorder(),
                      hintText: 'Password',
                    ),
                  )),
              CustomWidgets.socialButtonRect('Login with Facebook',
                  facebookColor, FontAwesomeIcons.facebookF, onTap: () async {
                await signInWithFacebook();
              }),
              Padding(
                padding: const EdgeInsets.all(15.0),
                child:
                    loading ? const CircularProgressIndicator() : Container(),
              ),
            ],
          ),
        ), // This trailing comma makes auto-formatting nicer for build methods.
      ),
      onWillPop: () async {
        final shouldPop = await showDialog<bool>(
          context: context,
          builder: (context) {
            return AlertDialog(
              title: const Text('Do you want to go exit?'),
              actionsAlignment: MainAxisAlignment.spaceBetween,
              actions: [
                TextButton(
                  onPressed: () {
                    Navigator.pop(context, true);
                  },
                  child: const Text('Yes'),
                ),
                TextButton(
                  onPressed: () {
                    Navigator.pop(context, false);
                  },
                  child: const Text('No'),
                ),
              ],
            );
          },
        );
        return shouldPop!;
      },
    );
  }

  Future<void> signInWithFacebook() async {
    final LoginResult loginResult =
        await FacebookAuth.instance.login(permissions: ['email']);

    // Create a credential from the access token
    final OAuthCredential facebookAuthCredential =
        FacebookAuthProvider.credential(loginResult.accessToken!.token);

    final userData = await FacebookAuth.instance.getUserData();
    FirebaseAuth.instance.signInWithCredential(facebookAuthCredential);

    var snapshot = await FirebaseFirestore.instance
        .collection('users')
        .where('Email', isEqualTo: userData['email'])
        .get();

    if (snapshot.size == 0) {
      await FirebaseFirestore.instance
          .collection('users')
          .add({'Email': userData["email"], 'Name': userData['name']});
    }
    //userEmail = userData["email"];
    UserModel user = UserModel.fromJson(userData);
    _currentUser = user;
    setState(() {
      loading = true;
    });
    Navigator.pushNamed(context, '/home');
  }
}

home_page.dart

class HomePage extends StatefulWidget {
  const HomePage({Key? key}) : super(key: key);

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  final FirebaseAuth auth = FirebaseAuth.instance;
  bool loading = false;
  String name = "";

  @override
  Widget build(BuildContext context) {
    getName();
    return Scaffold(
      backgroundColor: Colors.blue,
      bottomNavigationBar: const BottomBar(),
      body: SafeArea(
        child: Column(
          children: [
            ListView.builder(
                scrollDirection: Axis.vertical,
                shrinkWrap: true,
                itemCount: 2,
                itemBuilder: (context, index) {
                  return matchTile();
                }),
            Center(
              child: ElevatedButton(
                onPressed: () async {
                  //Navigator.pop(context,true);
                  //Navigator.popUntil(context, ModalRoute.withName('/login'));
                  Navigator.of(context).pushReplacementNamed('/login');
                  await signOut();
                },
                child: Text(name),
                style: TextButton.styleFrom(
                  primary: Colors.redAccent,
                  onSurface: Colors.red,
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }

  Future<void> signOut() async {
    await FacebookAuth.i.logOut();
    await FirebaseAuth.instance.signOut();
  }

  Future<void> getName() async {
    User? user = auth.currentUser;
    await user?.reload();
    user = auth.currentUser;
    String? temp = user?.email;

    var snapshot = await FirebaseFirestore.instance
        .collection('users')
        .where('Email', isEqualTo: temp)
        .limit(1)
        .get()
        .then((value) => value.docs[0]);
    Map<String, dynamic> data = snapshot.data();
    //print('the lenght : $data.length');
    setState(() {
      name = data['Name'];
    });
  }
}

For last these are the rules I have set in firebase

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
          allow read, write: if request.auth != null;
    }
  }
}

CodePudding user response:

You probably are missing an await.

Without this await the user is not logged when accessing Firestore, as the code "just runs by".

await FirebaseAuth.instance.signInWithCredential(facebookAuthCredential);
  • Related