如何使用共享首选项让用户保持登录状态?

Posted

技术标签:

【中文标题】如何使用共享首选项让用户保持登录状态?【英文标题】:How to use shared preferences to keep user logged in flutter? 【发布时间】:2019-06-19 23:47:47 【问题描述】:

我想在用户成功登录flutter后保持用户登录状态。 我正在使用 REST API 来检索用户的用户名和密码。但我想保存这些详细信息,以便用户可以保持登录状态。我目前的情况是我可以成功登录用户,但是当我重新启动应用程序时,我必须再次登录,所以我需要将用户的详细信息保存在共享偏好,以便用户可以在整个会话中保持登录状态,直到注销。但我无法做到这一点,所以请帮助我。 提前致谢

这是我登录页面的代码。 我已经删除了应该在列表视图中的 UI 内容,因为这些内容并不相关。

登录.dart

import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:restaurant_app/globalVar.dart';
import 'package:restaurant_app/homescreen.dart';
import 'package:restaurant_app/models/auth.dart';
import 'package:restaurant_app/signup.dart';
import 'package:http/http.dart' as http;
import 'package:restaurant_app/utils/authutils.dart';
import 'package:shared_preferences/shared_preferences.dart';

class SignIn extends StatefulWidget 

    SignIn( Key key, this.post ): super(key: key);

@override
_SignInState createState() => _SignInState();
    

class _SignInState extends State<SignIn> with SingleTickerProviderStateMixin 
    
    TabController controller;
    TextEditingController _email = new TextEditingController();
    TextEditingController _password = new TextEditingController();
    bool loading;

    final GlobalKey < ScaffoldState > _scaffoldKey = new GlobalKey<ScaffoldState>
        ();

    @override
    void initState() 
        // TODO: implement initState
        super.initState();
        _fetchSessionAndNavigate();
        controller = new TabController(length: 2, vsync: this);
        loading = false;
    

    @override
    void dispose() 
        // TODO: implement dispose
        super.dispose();
        controller.dispose();
        setState(() 
            loading = false;
        );
        _email.dispose();
        _password.dispose();
    

    final GlobalKey < FormState > _formKey = GlobalKey<FormState>();
    bool _autoValidate = false;

    _login(username, password) async 
        setState(() 
            loading = true;
        );

        var body = json.encode(
            "username": username,
            "password": password,
        );

        Map < String, String > headers = 
            'Content-type': 'application/json',
                'Accept': 'application/json',
      ;

        await http
            .post("$GlobalVar.Ip/wp-json/jwt-auth/v1/token",
                body: body, headers: headers)
            .then((response) 
                var body = json.decode(response.body);
                //var response1;

                if (response.statusCode == 200) 
                    // TODO: you need to store body['token'] to use in some authentication
                    loading = false;
                    Navigator.pushReplacement(context,
                        MaterialPageRoute(builder: (BuildContext ctx) => HomePage()));
     else 
        // TODO: alert message
        final snackBar = SnackBar(
            content: Text(body['message'].toString().trim()),
        );
        _scaffoldKey.currentState.showSnackBar(snackBar);
    
    setState(() 
        loading = false;
    );
);
      

@override
Widget build(BuildContext context) 
    return Scaffold(
        key: _scaffoldKey,
        resizeToAvoidBottomPadding: false,
        body: Container(
            decoration: BoxDecoration(
                image: DecorationImage(
                    image: AssetImage('images/art.png'),
                    fit: BoxFit.fill,
                    colorFilter: ColorFilter.mode(
                        Colors.white12.withOpacity(0.2), BlendMode.dstATop),
                ),
            ),
            child: ListView();

【问题讨论】:

那是很多代码。我建议您(1)将代码减少到最少的相关部分,并(2)解释您要做什么以及问题所在。见***.com/help/how-to-ask 谢谢 Edman...我已经做出了改变 【参考方案1】:

如果用户详细信息保存在存储中,您可以导航到Login 页面,否则使用以下代码导航到Home 页面

  Future<void> main() async 
      WidgetsFlutterBinding.ensureInitialized();
      SharedPreferences prefs = await SharedPreferences.getInstance();
      var email = prefs.getString('email');
      print(email);
      runApp(MaterialApp(home: email == null ? Login() : Home()));
    

登录成功后保存所需的用户详细信息

class Login extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    return Scaffold(
      body: Center(
        child: RaisedButton(
          onPressed: () async 
            //after the login REST api call && response code ==200
            SharedPreferences prefs = await SharedPreferences.getInstance();
            prefs.setString('email', 'useremail@gmail.com');
            Navigator.pushReplacement(context,
                MaterialPageRoute(builder: (BuildContext ctx) => Home()));
          ,
          child: Text('Login'),
        ),
      ),
    );
  

注销时清除详细信息

class Home extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    return Scaffold(
      appBar: AppBar(
        title: Text('Home'),
      ),
      body: Center(
        child: RaisedButton(
          onPressed: () async 
            SharedPreferences prefs = await SharedPreferences.getInstance();
            prefs.remove('email');
            Navigator.pushReplacement(context,
                MaterialPageRoute(builder: (BuildContext ctx) => Login()));
          ,
          child: Text('Logout'),
        ),
      ),
    );
  

希望对你有帮助!

【讨论】:

我很困惑..你能根据我的代码写一些东西吗,因为我是 rest api 和共享偏好的新手,所以我很难理解代码 这是您编辑的代码gist.github.com/shyjuzz/054f783e8b7c3a2e852af326f0db375f 这对我不起作用。 SharedPreferences 首选项 = 等待 SharedPreferences.getInstance();正在为我抛出错误。完全混乱.... @NullPointer 你得到什么错误?您是否在 pubspec 文件中添加了包? 确保 WidgetFlutterBinding.ensureInitialized() 是 main() 的第一行 ***.com/a/57775690/11535769【参考方案2】:

确保WidgetFlutterBinding.ensureInitialized()是main()的第一行

import 'package:shared_preferences/shared_preferences.dart';
import 'package:flutter/material.dart';

Future<void> main() async 
  WidgetsFlutterBinding.ensureInitialized();
  SharedPreferences prefs = await SharedPreferences.getInstance();
  bool login = prefs.getBool("login");
  print("login:" + login.toString());
  runApp(MaterialApp(home: login == null ? LoginPage(title: 'My App') : HomePage()));


class LoginPage extends StatelessWidget  ...

【讨论】:

【参考方案3】:

上述使用SharedPreferences 的答案有效(确保您将WidgetsFlutterBinding.ensureInitiazed(); 作为您的第一行main),但它会在重新启动时为您提供null,即,如果您从最近删除应用程序并重新- 再次打开它,它不会将您重定向到主页或个人资料页面。我通过向您的应用授予写入外部存储权限来解决此问题,因为共享首选项需要将数据写入您的设备或模拟器中的某个位置。

只需在您的 android Manifest 文件中添加写入和读取外部存储权限,您就可以使用 pub.dev 中 Flutter 的 permission_handler 插件,在应用程序第一次打开然后共享时在运行时从用户那里获取所需的权限首选项不会给你null

【讨论】:

【参考方案4】:

改用用户会话。查看Consession。该软件包在 Flutter 中添加了用户会话支持,并且易于使用。

// Store value to session
await Consession().set("token", myJWTToken);

// Retrieve item from session
dynamic token = await Consession().get("token");

【讨论】:

【参考方案5】:

现在不赞成使用特许权以支持flutter_session。我们现在可以使用 flutter_session 无缝管理用户会话。

//Write values to the session: 
await FlutterSession().set("token", myJWTToken);

//Read values from the session: 
dynamic token = await FlutterSession().get("token");

【讨论】:

嘿!我在使用 FlutterSession 时遇到问题。你能帮帮我吗? ***.com/questions/66311232/… 对不起@CodeSadhu 我不是颤振专家。我正在尝试一些非常具体的事情并遇到了这个问题,我现在似乎都不记得了:P

以上是关于如何使用共享首选项让用户保持登录状态?的主要内容,如果未能解决你的问题,请参考以下文章

Flutter Web:保持用户登录/记住我功能的正确方法

Firebase:如何让 Android 用户保持登录状态?

如何让用户使用 JWT 登录 Flutter 应用程序?

我是 Flutter Web 的新手,如何使用 Firebase 电话身份验证对用户进行身份验证,有没有办法让用户保持登录状态?

在导致空指针的活动中使用共享首选项,这让我起了作用

如何使用 Xamarin 在设备之间共享用户首选项