如何在Flutter中管理Firebase身份验证状态? [英] How to manage Firebase Authentication state in Flutter?

查看:112
本文介绍了如何在Flutter中管理Firebase身份验证状态?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 WelcomeScreen ,其中包含注册和登录以及 HomeScreen ,我想在用户之后重定向到该位置登录。为了管理身份验证数据,我创建了一个 auth.dart ,其中包含 static 属性和方法,因此我可以访问

  import'package:firebase_auth / firebase_auth.dart'; 

class Auth {

static final auth = FirebaseAuth.instance;

静态Future< void> logout()async {
等待auth.signOut();
}

静态Future< void> loginUser(String userEmail,String userPassword)异步{
等待auth.signInWithEmailAndPassword(电子邮件:userEmail,密码:userPassword);
}

静态Future< FirebaseUser> getCurrentUser()async {
return await auth.currentUser();
}
}

main.dart 文件,我正在使用 StreamBuilder 根据更改身份验证数据来更改当前屏幕。我从



[我将其添加为单独的答案,因为它使用了提供程序包]



而不是使变量和 Auth 类中的方法 static ,则应使用 Provider 或其他一些型号。我在 Auth 类中使用 bool 变量来跟踪登录,您可以根据需要修改该类。

  void main(){
WidgetsFlutterBinding.ensureInitialized();

runApp(
ChangeNotifierProvider< Auth>(
create:(_)=> Auth(),
子代:MaterialApp(home:MyApp()),
),
);
}

类MyApp扩展了StatelessWidget {
@override
Widget build(BuildContext context){
return Consumer< Auth>(
builder :(_,auth,__){
if(auth.loggedIn)返回HomeScreen();
返回WelcomeScreen();
},
);
}
}

类HomeScreen扩展StatelessWidget {
@override
Widget build(BuildContext context){
return Scaffold(
appBar:AppBar(标题:文本('主屏幕')),
floatActionButton:FloatingActionButton.extended(
标签:Text('登出'),
onPressed:()异步{
final auth = Provider.of< Auth>(上下文,侦听:false);
等待auth.logout();
},
),
);
}
}

类WelcomeScreen扩展了StatelessWidget {
@override
Widget build(BuildContext context){
return Scaffold(
appBar:AppBar(标题:文本('欢迎屏幕')),
正文:中心(
子对象:RaisedButton(
onPressed:()=> Navigator.pushReplacement(context,MaterialPageRoute (builder:(_)=> LoginPage())),
子级:Text('Go to Login Page'),
),
),
);
}
}

类LoginPage扩展StatelessWidget {
@override
Widget build(BuildContext context){
return Scaffold(
appBar:AppBar(标题:文本('登录页面')),
正文:Center(
子级:RaisedButton(
onPressed:()异步{
final auth =提供者.of< Auth>(上下文,监听:false);
等待auth.loginUser('test@test.com','test1234');
等待Navigator.pushReplacement(上下文,MaterialPageRoute(builder: (_)=> MyApp()));
},
子级:Text('Login'),
),
),
);
}
}

使用ChangeNotifier的Auth类{
final _auth = FirebaseAuth.instance;
bool _loggedIn = false;

bool获取登录=> _登录;

Future< void> logout()async {
await _auth.signOut();
_loggedIn = false;
notifyListeners();
}

Future< void> loginUser(String userEmail,String userPassword)async {
await _auth.signInWithEmailAndPassword(电子邮件:userEmail,密码:userPassword);
_loggedIn = true;
notifyListeners();
}

Future< FirebaseUser> getCurrentUser()async {
return wait _auth.currentUser();
}
}

现在,即使您正在登录,也可以看到从 LoginPage 进入,它不是您的消费者的直接子代,您可以看到其登录状态更改时,仍会调用builder 。但是,当您导航到 LoginPage 时,由于小部件树显示的是 LoginPage 。在上一个示例中,我导航到 HomeScreen ,但是在此示例中,我弹出了。


I have a WelcomeScreen which contains sign up and login and the HomeScreen where I want to redirect after the user logs in. To manage auth data, I have created an auth.dart with static properties and methods so I can access them across all pages with same data.

import 'package:firebase_auth/firebase_auth.dart';

class Auth {

  static final auth = FirebaseAuth.instance;

  static Future<void> logout() async {
    await auth.signOut();
  }

  static Future<void> loginUser(String userEmail, String userPassword) async {
    await auth.signInWithEmailAndPassword(email: userEmail, password: userPassword);
  }

  static Future<FirebaseUser> getCurrentUser() async {
    return await auth.currentUser();
  }
}

In main.dart file, I am using StreamBuilder to change the current screen based on changing auth data. I got this StreamBuilder code from this answer.

home: StreamBuilder<FirebaseUser>(
  stream: Auth.auth.onAuthStateChanged,
  builder: (context, snapshot) {
    if (snapshot.hasData) {
      return HomeScreen();
    } else {
      return WelcomeScreen();
    }
  },
),

In my login screen, I am using the below code to trigger log in:

Future<void> login() async {
    ...

    try {
      await Auth.loginUser(userEmail, userPassword);
      var user =  await Auth.getCurrentUser();
      print(user.displayName); // This works
    } catch (error) {
      print(error.message);
    }
  }

I don't know whether the static methods I am using are the correct way to handle Firebase auth or not but it seems to work. After logging in, I am able to display the name of the logged in user but the StreamBuilder in main.dart is not reflecting the updated auth data, i.e not changing the page.

Is it because of static methods or something wrong in the implementation of StreamBuilder?

解决方案

[I am adding this as a separate answer because it uses provider package]

Instead of making your variables and methods static in Auth class, you should use Provider or some other models. I am using a bool variable in Auth class to keep track of login, you can modify the class according to your needs.

void main() {
  WidgetsFlutterBinding.ensureInitialized();

  runApp(
    ChangeNotifierProvider<Auth>(
      create: (_) => Auth(),
      child: MaterialApp(home: MyApp()),
    ),
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Consumer<Auth>(
      builder: (_, auth, __) {
        if (auth.loggedIn) return HomeScreen();
        return WelcomeScreen();
      },
    );
  }
}

class HomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Home Screen')),
      floatingActionButton: FloatingActionButton.extended(
        label: Text('Sign out'),
        onPressed: () async {
          final auth = Provider.of<Auth>(context, listen: false);
          await auth.logout();
        },
      ),
    );
  }
}

class WelcomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Welcome Screen')),
      body: Center(
        child: RaisedButton(
          onPressed: () => Navigator.pushReplacement(context, MaterialPageRoute(builder: (_) => LoginPage())),
          child: Text('Go to Login Page'),
        ),
      ),
    );
  }
}

class LoginPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Login Page')),
      body: Center(
        child: RaisedButton(
          onPressed: () async {
            final auth = Provider.of<Auth>(context, listen: false);
            await auth.loginUser('test@test.com', 'test1234');
            await Navigator.pushReplacement(context, MaterialPageRoute(builder: (_) => MyApp()));
          },
          child: Text('Login'),
        ),
      ),
    );
  }
}

class Auth with ChangeNotifier {
  final _auth = FirebaseAuth.instance;
  bool _loggedIn = false;

  bool get loggedIn => _loggedIn;

  Future<void> logout() async {
    await _auth.signOut();
    _loggedIn = false;
    notifyListeners();
  }

  Future<void> loginUser(String userEmail, String userPassword) async {
    await _auth.signInWithEmailAndPassword(email: userEmail, password: userPassword);
    _loggedIn = true;
    notifyListeners();
  }

  Future<FirebaseUser> getCurrentUser() async {
    return await _auth.currentUser();
  }
}

Now you can see, even when you're logging in from LoginPage which isn't a direct child of your Consumer, you can see its builder is still getting called when login status changes. However, when you navigate to LoginPage, you need to make a pop to get back to the previous page because your widget tree was displaying LoginPage only. In my previous example I was navigating to HomeScreen, but in this one I am popping.

这篇关于如何在Flutter中管理Firebase身份验证状态?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆