简体   繁体   English

如何在 Flutter 中保存用户登录详细信息?

[英]How to save user sign-in details in Flutter?

I am new to flutter and want to make an app which only authenticated users (via filling email and password) can use.我是 flutter 的新手,想制作一个只有经过身份验证的用户(通过填写电子邮件和密码)才能使用的应用程序。 So I am thinking of making a root widget called Authentication where I will check if the user is authenticated or not.因此,我正在考虑制作一个名为Authentication的根小部件,我将在其中检查用户是否已通过身份验证。 If they are then take them to Home() Widget (which is basically app home page) else to SignIn() Widget (which is signin page) .如果他们然后将他们带到Home() Widget(基本上是应用程序主页)或 SignIn() Widget(这是登录页面)。

  • I have to check for user authentication in 2 senerios:我必须在 2 种情况下检查用户身份验证:
    • When app opens so that previously signed in user does not have to signin again当应用程序打开时,以前登录的用户不必再次登录
    • After filling up Email-Id and Password user clicks on Sign In button填写电子邮件 ID 和密码后,用户点击Sign In按钮

I am facing the following problem and don't know how do I solve them ( Assume that there is no signup option and user data is entered to db directly not through some UI ):我面临以下问题,不知道如何解决它们(假设没有注册选项并且用户数据不是通过某些 UI 直接输入到数据库中的):

  • If a user is already signed in how to take them directly to Home() Widget ?如果用户已经登录,如何将他们直接带到Home() Widget ?

    This is code of what I have currently I am not sure if is the right way of doing this type of app so if there is a better way to do this please tell :这是我目前拥有的代码我不确定是否是做这种类型的应用程序的正确方法所以如果有更好的方法来做到这一点请告诉:


    import 'package:flutter/material.dart';
    import 'package:myapp/home.dart';
    import 'package:myapp/signIn.dart';


    void main() => runApp(Authenticate());

    class Authenticate extends StatelessWidget {


      final String authenticateEmail;
      final String authenticatePassword;

      Authenticate({this.authenticateEmail, this.authenticatePassword}); 




      // Make a call to db to check if the data provided is correct or not 
      // If it is correct we then navigate the user to Home() Widget 
      // Else to SignIn() Widget

  @override
  Widget build(BuildContext context) {

     if ( make some call to db to check if data is there) {
       return Home();
     }
     else {
       return SignIn();
     }

  }
}

The issue with above code is when the app is opened for the first time how to take user directly to SignIn() Widget should I initilize the fields with empty string and in method check for condition if string is empty or not ?上面代码的问题是当应用程序第一次打开时如何将用户直接带到 SignIn() Widget 我应该用空字符串初始化字段并在方法中检查条件是否字符串为空?

Create a sqlite table and then when authenticating user is successful from server save required details to local table (delete any previous row saved before saving).创建一个 sqlite 表,然后当从服务器验证用户成功时将所需的详细信息保存到本地表(删除保存前保存的任何先前的行)。

Now just check on app start that whether user table is empty or not and decide where the flow should be.现在只需检查应用程序启动用户表是否为空并决定流应该在哪里。

On first run table will be empty by default so it will show login page默认情况下,第一次运行表将为空,因此它将显示登录页面

APP RUN -> Check if row exists in user table

if YES ->  return Home();
else -> return SignIn();

Use user sessions instead.改用用户会话。 Check out FlutterSession .查看FlutterSession The package adds user session support in Flutter and is easy to use.该包在 Flutter 中添加了用户会话支持,并且易于使用。

bool isAuth = Authenticate({this.authenticateEmail, this.authenticatePassword});

// Store value to session
await FlutterSession().set("isAuth", isAuth);

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

The root widget which you are calling Authentication is the app.您调用Authentication的根小部件是应用程序。

In pubspec.yaml add two dependenciespubspec.yaml添加两个依赖

provider: ^4.0.3
shared_preferences: ^0.5.6+1

Similar to the example, I wrote on Flutter provider state management, logout concept .类似的例子,我写过Flutter provider state management, logout concept

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

// If successful, returns a token. Otherwise throws an error.
typedef Future<String> SignIn({
  @required final String username,
  @required final String password,
});

// If successful, returns void. Otherwise throws an error.
typedef Future<void> SignOut({
  @required final String token,
});

// ----------------------------------------------------------------------------

class Session with ChangeNotifier {
  String _token; // can be null
  final SignIn _signIn;
  final SignOut _signOut;

  Session({
    @required String token,
    @required SignIn signIn,
    @required SignOut signOut,
  })  : assert(signIn != null),
        assert(signOut != null),
        this._token = token,
        this._signIn = signIn,
        this._signOut = signOut;

  Future<void> signIn({
    @required final String username,
    @required final String password,
  }) async {
    assert(username != null);
    assert(password != null);

    final String token = await this._signIn(
      username: username,
      password: password,
    );
    this._token = token;
    this.notifyListeners();
  }

  Future<void> signOut() async {
    await this._signOut(token: this._token);
    this._token = null;
    this.notifyListeners();
  }

  bool get isAuthenticated {
    return (this._token != null);
  }
}

// ----------------------------------------------------------------------------

Future<void> main() async {
  // The app would load and present an error message on screen to add the following line.
  // https://github.com/flutter/flutter/issues/39620
  // https://api.flutter.dev/flutter/widgets/WidgetsFlutterBinding/ensureInitialized.html
  WidgetsFlutterBinding.ensureInitialized();

  // Initialize some local persistence.
  // Could be SQLite or somewhere encrypted.
  SharedPreferences prefs = await SharedPreferences.getInstance();

  final Session session = Session(
    token: prefs.getString('token'),
    signIn: ({
      @required final String username,
      @required final String password,
    }) async {
      assert(username != null);
      assert(password != null);

      // Contact the server to validate credentials and get token.
      await Future.delayed(Duration(milliseconds: 500)); // network delay
      if ((username != 'johnsmith') || (password != 'opensesame')) {
        throw new Exception("bad username or password");
      } else {
        final String token = '9djdhy89032jfdhdf70912';
        // Store the token locally.
        prefs.setString('token', token);
        return token;
      }
    },
    signOut: ({@required final String token}) async {
      assert(token != null);

      // Contact the server to sign out.
      await Future.delayed(Duration(milliseconds: 500)); // network delay
      // Update the local storage.
      prefs.setString('token', null);
    },
  );

  return runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider<Session>.value(value: session),
      ],
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(final BuildContext context) {
    return Consumer<Session>(
      builder: (final BuildContext context, final Session session, final Widget child) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(primarySwatch: Colors.blue),
          home: session.isAuthenticated ? MyHomePage() : MySignInPage(),
        );
      },
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(final BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("Home [Auth Protected]")),
      body: Center(
        child: RaisedButton(
          child: const Text("Sign Out"),
          onPressed: () {
            final Session session = Provider.of<Session>(context, listen: false);
            session.signOut();
          },
        ),
      ),
    );
  }
}

// Of course this would have username and password inputs and a submit button.
class MySignInPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("Sign In")),
      body: Center(
        child: RaisedButton(
          child: const Text("Sign In with johnsmith, opensesame"),
          onPressed: () {
            final Session session = Provider.of<Session>(context, listen: false);
            session.signIn(username: 'johnsmith', password: 'opensesame');
          },
        ),
      ),
    );
  }
}

You can use您可以使用

shared_preferences: xxx (version) shared_preferences: xxx (版本)

package to store user response.用于存储用户响应的包。

Example (Using DIO for HTTP Request) :示例(使用 DIO 进行 HTTP 请求):

Future<bool> saveUser(String user) async {
final prefs = await SharedPreferences.getInstance();
return prefs.setString('', user);
}

Future<dynamic> login(String username, String password) async {


try {
  var res = await dio.post("LOGIN-URL",
      data: {"user": username, "pass": password});

  if (res.statusCode==200) {
        
    final userIsStored =
        await saveUser(jsonEncode(res.data));
       
    if (userIsStored) {
      print('USER HAS BE STORED TO SHAREDPREFERENCES');
    }
    User.fromJson(res.data);
  } else {
  }
} catch (e) {
  throw e.response;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM