保留用户身份验证 Flutter Firebase

问题描述 投票:0回答:8

我在 Flutter 中使用 Firebase Auth 和 google 登录。我可以登录,但是当我关闭应用程序(杀死它)时,我必须重新注册。那么有没有一种方法可以保留用户身份验证,直到用户专门注销为止? 这是我的授权类

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

class Auth {
  FirebaseAuth _firebaseAuth;
  FirebaseUser _user;

  Auth() {
    this._firebaseAuth = FirebaseAuth.instance;
  }

  Future<bool> isLoggedIn() async {
    this._user = await _firebaseAuth.currentUser();
    if (this._user == null) {
      return false;
    }
    return true;
  }

  Future<bool> authenticateWithGoogle() async {
    final googleSignIn = GoogleSignIn();
    final GoogleSignInAccount googleUser = await googleSignIn.signIn();
    final GoogleSignInAuthentication googleAuth =
    await googleUser.authentication;
    this._user = await _firebaseAuth.signInWithGoogle(
      accessToken: googleAuth.accessToken,
      idToken: googleAuth.idToken,
    );
    if (this._user == null) {
      return false;
    }
    return true;
    // do something with signed-in user
  }
}

这是我的起始页面,其中调用了身份验证检查。

import 'package:flutter/material.dart';
import 'auth.dart';
import 'login_screen.dart';
import 'chat_screen.dart';

class Splash extends StatefulWidget {

  @override
  _Splash createState() => _Splash();
}

class _Splash extends State<Splash> {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: CircularProgressIndicator(
          value: null,
        ),
      ),
    );
  }

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

  Future<void> _handleStartScreen() async {
    Auth _auth = Auth();
    if (await _auth.isLoggedIn()) {
      Navigator.of(context).pushReplacementNamed("/chat");
    }
    Navigator.pushReplacement(context, MaterialPageRoute(builder: (BuildContext context) => LoginScreen(auth: _auth,)));
  }
}
firebase flutter firebase-authentication
8个回答
23
投票

我相信你的问题是路由。在我的应用程序中,我使用

FirebaseAuth
,它的工作原理就像你说的那样,而且我不保留任何登录令牌。但是,我不知道为什么你使用 getUser 的方法不起作用。

尝试调整您的代码以使用

onAuthStateChanged
。编辑:截至 2022 年,对于 Flutter 3,我注意到使用
userChanges
效果更好。

基本上,在您的

MaterialApp
上,创建一个
StreamBuilder
监听
_auth.userChanges()
并根据身份验证状态选择您的页面。

我将复制并粘贴我的应用程序的部分内容,以便您有一个想法(见下文)。

[...]

final FirebaseAuth _auth = FirebaseAuth.instance;

Future<void> main() async {
  FirebaseApp.configure(
    name: '...',
    options:
      Platform.isIOS
        ? const FirebaseOptions(...)
        : const FirebaseOptions(...),
    );
  
  [...]  

  runApp(new MaterialApp(
    title: '...',
    home: await getLandingPage(),
    theme: ThemeData(...),
  ));
}

Future<Widget> getLandingPage() async {
  return StreamBuilder<FirebaseUser>(
    stream: _auth.userChanges(),
    builder: (BuildContext context, snapshot) {
      if (snapshot.hasData && (!snapshot.data!.isAnonymous)) {
        return HomePage();
      }
      
      return AccountLoginPage();
    },
  );
}

更新:截至 2024 年,我相信推荐的方法是使用 go_router。从这个意义上说,该代码将更改为类似以下内容:

[...]

  final GoRouter _router = GoRouter(
    refreshListenable: GoRouterRefreshStream(FirebaseAuth.instance.userChanges()),

  runApp(MaterialApp.router(
    [...]
    routeInformationProvider: _router.routeInformationProvider,
    routeInformationParser: _router.routeInformationParser,
    routerDelegate: _router.routerDelegate,
  ));

[...]

但是(抱歉!),似乎 GoRouterRefreshStream 已从 go_router 中删除,然后我还不知道新的做法是什么。


3
投票

抱歉,这是我的错误。忘记将推送登录屏幕放在 else 中。

  Future<void> _handleStartScreen() async {
    Auth _auth = Auth();
    if (await _auth.isLoggedIn()) {
      Navigator.of(context).pushReplacementNamed("/chat");
    }
    else {
        Navigator.pushReplacement(context, MaterialPageRoute(builder: (BuildContext context) => LoginScreen(auth: _auth,)));
    }
  }

2
投票
void main() {
FirebaseAuth.instance.authStateChanges().listen((User user) {
  if (user == null) {
          runApp(MyApp(auth : false);
        } else {
          runApp(MyApp(auth : false);
       }
    });
}

class MyApp extends StatefulWidget {
  final bool auth;
  MyApp({this.auth});
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  return MaterialApp(
  ......
  ......
  home: widget.auth ? MainScreen() : AuthScreen();
);

1
投票

即使您终止了应用程序,您也可以使用

shared_preferences
来保持会话处于活动状态。 这是文档https://pub.dartlang.org/packages/shared_preferences

我还听说可以使用 sqlite 来持久化会话。


1
投票

添加此代码。应该可以正常工作。

FirebaseAuth auth = FirebaseAuth.instance;

auth.setPersistence(Persistence.SESSION);

0
投票

你可以使用我的代码,你可以使用 userChanges() 而不是 authStateChanges()

通知任何用户更新的更改。

这是 [authStateChanges] 和 [idTokenChanges] 的超集。它提供所有用户更改的事件,例如何时链接、取消链接凭证以及何时更新用户配置文件。此流的目的是监听用户状态的实时更新(登录、注销、不同用户和令牌刷新),而无需手动调用 [reload],然后重新对应用程序进行更改。

final Stream<User?> firebaseUserChanges = firebaseAuth.userChanges();

0
投票

再举一个简单的例子:

Future<bool> isUserLoggedIn() async {
   final User? user = FirebaseAuth.instance.currentUser;
   return user != null;
}


class InitialScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: FutureBuilder<bool>(
        future: isUserLoggedIn(),
        builder: (_, snapshot) {
          if (snapshot.hasData) {
            if (snapshot.data ?? false) {
              Navigator.of(context).push(MaterialPageRoute(builder: (context) => UnauthScreen()));
            } else {
              Navigator.of(context).push(MaterialPageRoute(builder: (context) => HomeScreen()));
            }
          }
         return const Center(child: CircularProgressIndicator());
       },
      ),
    );
   }
 }

0
投票

我可以通过检查 firebase 实例 currentUser 值来实现它。如果为 null,我将路由到我的注册页面。如果没有,那么我就会路由到我的主页。不确定这个实现是否有任何问题(到目前为止运行良好),但似乎比上面发布的 StreamBuilder 解决方案更简单。

  home: getLandingPage(),
        routes: {
          (...)
 }

    Widget getLandingPage() {
  if (_auth.currentUser == null) {
    return SignupPage();
  } else {
    return HomePage();
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.