使用onAuthStateChanged通过Flutter登录Firebase

Gil*_*erg 11 dart firebase firebase-authentication google-signin flutter

在Flutter之外,当我实现firebase身份验证时,我总是使用firebase提供的onAuthStateChanged侦听器来确定用户是否已登录并相应地做出响应.

我正在尝试使用flutter做类似的事情,但我可以找到一种方法来访问Firebase的onAuthStateChanged.我正在使用firebase_auth和google_signin Flutter插件.我正在使用firebase_auth Flutter插件中包含的示例代码.下面是示例代码.我可以使用谷歌登录成功登录,但示例太简单了,因为我想让观察者/监听器检测用户的登录/退出状态.

有没有办法通过观察者/监听器使用firebase_auth/google_signin flutter插件来检测以确定用户的状态?

最终,我希望应用程序确定用户是否已登录(是/否).如果没有,则显示登录屏幕,如果是,则显示我的主应用程序页面.

import 'dart:async';
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';

final FirebaseAuth _auth = FirebaseAuth.instance;
final GoogleSignIn _googleSignIn = new GoogleSignIn();

void main() {
  runApp(new MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Firebase Auth Demo',
      home: new MyHomePage(title: 'Firebase Auth Demo'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  Future<String> _message = new Future<String>.value('');

  Future<String> _testSignInAnonymously() async {
    final FirebaseUser user = await _auth.signInAnonymously();
    assert(user != null);
    assert(user == _auth.currentUser);
    assert(user.isAnonymous);
    assert(!user.isEmailVerified);
    assert(await user.getToken() != null);
    if (Platform.isIOS) {
      // Anonymous auth doesn't show up as a provider on iOS
      assert(user.providerData.isEmpty);
    } else if (Platform.isAndroid) {
      // Anonymous auth does show up as a provider on Android
      assert(user.providerData.length == 1);
      assert(user.providerData[0].providerId == 'firebase');
      assert(user.providerData[0].uid != null);
      assert(user.providerData[0].displayName == null);
      assert(user.providerData[0].photoUrl == null);
      assert(user.providerData[0].email == null);
    }
    return 'signInAnonymously succeeded: $user';
  }

  Future<String> _testSignInWithGoogle() async {
    final GoogleSignInAccount googleUser = await _googleSignIn.signIn();
    final GoogleSignInAuthentication googleAuth =
        await googleUser.authentication;
    final FirebaseUser user = await _auth.signInWithGoogle(
      accessToken: googleAuth.accessToken,
      idToken: googleAuth.idToken,
    );
    assert(user.email != null);
    assert(user.displayName != null);
    assert(!user.isAnonymous);
    assert(await user.getToken() != null);
    return 'signInWithGoogle succeeded: $user';
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text(widget.title),
      ),
      body: new Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          new MaterialButton(
              child: const Text('Test signInAnonymously'),
              onPressed: () {
                setState(() {
                  _message = _testSignInAnonymously();
                });
              }),
          new MaterialButton(
              child: const Text('Test signInWithGoogle'),
              onPressed: () {
                setState(() {
                  _message = _testSignInWithGoogle();
                });
              }),
          new FutureBuilder<String>(
              future: _message,
              builder: (_, AsyncSnapshot<String> snapshot) {
                return new Text(snapshot.data ?? '',
                    style: const TextStyle(
                        color: const Color.fromARGB(255, 0, 155, 0)));
              }),
        ],
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

以下是有问题的flutter包的链接:https : //github.com/flutter/plugins/tree/master/packages/firebase_auth https://github.com/flutter/plugins/tree/master/packages/google_sign_in

Jav*_*ash 23

我知道这个问题已经很老了,但如果有人还在寻找,那么这就是答案.

Firebase使用onAuthStateChanged函数返回FirebaseUser流.有许多方法可以监听用户的身份验证状态更改.我是这样做的:

解决方案1

我将StreamBuilder返回到我的应用程序主页,StreamBuilder根据用户的身份验证状态返回特定页面.

@override
Widget build(BuildContext context) {
  return MaterialApp(
      title: 'Your App Name',
      home: _getLandingPage()
  );
}

Widget _getLandingPage() {
  return StreamBuilder<FirebaseUser>(
    stream: FirebaseAuth.instance.onAuthStateChanged,
    builder: (BuildContext context, snapshot) {
      if (snapshot.hasData) {
        if (snapshot.data.providerData.length == 1) { // logged in using email and password
          return snapshot.data.isEmailVerified
              ? MainPage()
              : VerifyEmailPage(user: snapshot.data);
        } else { // logged in using other providers
          return MainPage();
        }
      } else {
        return LoginPage();
      }
    },
  );
}
Run Code Online (Sandbox Code Playgroud)

解决方案2

您也可以在应用程序的initState()功能中创建一个监听器.

@override
void initState() {
  super.initState();

  FirebaseAuth.instance.onAuthStateChanged.listen((firebaseUser) {
    // do whatever you want based on the firebaseUser state
  });
}
Run Code Online (Sandbox Code Playgroud)


Cop*_*oad 11

空安全代码(不含第 3 方包)

截屏:

在此处输入图片说明


要检查用户是否从应用程序的任何位置登录,请使用

bool signedIn = Auth.instance.isSignedIn;
Run Code Online (Sandbox Code Playgroud)

要登录,请使用

await Auth.instance.signIn(email: 'email', password: 'password');
Run Code Online (Sandbox Code Playgroud)

要退出,请使用

await Auth.instance.signOut();
Run Code Online (Sandbox Code Playgroud)

完整代码:


void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();

  runApp(
    MaterialApp(
      home: StreamBuilder<User?>(
        stream: Auth.instance.authStateChange(),
        builder: (_, snapshot) {
          final isSignedIn = snapshot.data != null;
          return isSignedIn ? HomePage() : LoginPage();
        },
      ),
    ),
  );
}

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('HomePage')),
      body: Center(
        child: ElevatedButton(
          onPressed: () => Auth.instance.signOut(),
          child: Text('Sign out'),
        ),
      ),
    );
  }
}

class LoginPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('LoginPage')),
      body: Center(
        child: ElevatedButton(
          onPressed: () => Auth.instance.signIn(email: 'test@test.com', password: 'test1234'),
          child: Text('Sign in'),
        ),
      ),
    );
  }
}

class Auth {
  static final instance = Auth._();
  Auth._();

  final FirebaseAuth _auth = FirebaseAuth.instance;
  bool get isSignedIn => _auth.currentUser != null;

  Stream<User?> authStateChange() => _auth.authStateChanges();

  Future<void> signIn({required String email, required String password}) => _auth.signInWithEmailAndPassword(email: email, password: password);

  Future<void> signOut() => _auth.signOut();
}
Run Code Online (Sandbox Code Playgroud)

使用provider包的相同代码:

检查这个答案


hum*_*ado 7

您可以在 AuthService 类中创建一个流作为 onAuthStateChanged 的​​ getter。为了帮助您管理状态,您可以使用 Provider 包。AuthService 类将扩展 ChangeNotifier 类。

class AuthService extends ChangeNotifier {

    final FirebaseAuth _auth = FirebaseAuth.instance;
    final GoogleSignIn _googleSignIn = new GoogleSignIn();

    // create a getter stream
    Stream<FirebaseUser> get onAuthStateChanged => _auth.onAuthStateChanged;

    //Sign in async functions here ..

}
Run Code Online (Sandbox Code Playgroud)

用 ChangeNotifierProvider 包裹你的 MaterialApp 并在 create 方法中返回一个 AuthService 类的实例,如下所示:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (context) => AuthService(),
      child: new MaterialApp(
      title: 'Firebase Auth Demo',
      home: Landing(),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

现在将登陆页面创建为无状态小部件。使用 Provider.of(context) 和流构建器来侦听身份验证更改并根据需要呈现登录页面或主页。

class Landing extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    AuthService auth = Provider.of<AuthService>(context);
    return StreamBuilder<FirebaseUser>(
      stream: auth.onAuthStateChanged,
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.active) {
          FirebaseUser user = snapshot.data;
          if (user == null) {
            return LogIn();
          }
          return Home();
        } else {
          return Scaffold(
            body: Center(
              child: CircularProgressIndicator(),
            ),
          );
        }
      },
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

您可以从官方 flutter 文档中阅读有关使用 provider 进行状态管理的更多信息。按照此链接:https : //flutter.dev/docs/development/data-and-backend/state-mgmt/simple


Fre*_*ook 5

火力地堡颤振程式码实验室有使用谷歌标志和火力地堡AUTH一个更深入的例子。

完成最后一步后,您将获得此_ensureLoggedIn功能,该功能用于检查用户是否已登录,如果未登录,则启动登录流程。

Future<Null> _ensureLoggedIn() async {
  GoogleSignInAccount user = googleSignIn.currentUser;
  if (user == null)
    user = await googleSignIn.signInSilently();
  if (user == null) {
    user = await googleSignIn.signIn();
    analytics.logLogin();
  }
  if (auth.currentUser == null) {
    GoogleSignInAuthentication credentials =
    await googleSignIn.currentUser.authentication;
    await auth.signInWithGoogle(
      idToken: credentials.idToken,
      accessToken: credentials.accessToken,
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

您可以修改此选项,以在应用启动时检查这些内容,并有条件地向预身份验证和后身份验证用户显示不同的视图,例如:

final auth = FirebaseAuth.instance;

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
        title: 'MyApp',
        home: (_checkLogin() == true ? new PostAuthScaffold() : new PreAuthScaffold())
    );
  }
}

bool _checkLogin() {
  GoogleSignInAccount user = googleSignIn.currentUser;
  return !(user == null && auth.currentUser == null);
}
Run Code Online (Sandbox Code Playgroud)

  • 嗨@FrederickCook-谢谢您的回答,我希望它也可以解决我的问题,但是当我调试_checkLogin()函数时,我看到auth.currentUser将始终返回Future &lt;FirebaseUser&gt;,即使在我拥有的设备上永远不会登录。因此_checkLogin()将始终返回true,并且在您的情况下,它将始终显示PostAuthScaffold()小部件。还是您体验不同? (4认同)
  • Firebase for Flutter Codelab 在任何地方都没有提到任何有关身份验证的内容。您共享的链接适用于使用 Firestore 的名称应用程序,与身份验证无关。您共享的 Github 链接确实包含一些授权代码行,但对于如何管理登录状态而言,这根本没有帮助。 (2认同)