【问题标题】:Manage social user details in Google Flutter application在 Google Flutter 应用程序中管理社交用户详细信息
【发布时间】:2020-01-27 08:52:53
【问题描述】:

我是开发 Flutter 应用程序的初学者,并尝试创建一个示例应用程序用于教育目的。上周我决定在 Flutter 中做一个示例应用程序,它没有内置登录或注册部分,因为它有 Facebook 和 Google 等社交登录选项。我在网上搜索了很多关于如何在 Flutter 应用程序中实现 Facebook 和 Google 身份验证的代码示例。

我对这种社交登录实现有疑问,可能是因为缺乏移动应用程序架构级别的工作经验。此时我在问自己一个问题“如何在应用程序中管理社交登录用户”

我有一个解决方案,比如如果用户可以成功登录,将用户详细信息存储到我们的(Firebase)数据库中,检查数据库中是否存在用户电子邮件如果数据库中没有匹配的条目,它将在数据库中创建一个新用户或如果存在,则更新该特定用户的上次登录日期时间。因为这个应用程序以其他形式显示了一些与用户相关的数据,它是基于登录的用户 ID 工作的,所以我需要将登录的用户详细信息存储在数据库中。

【问题讨论】:

    标签: flutter dart architecture cross-platform software-design


    【解决方案1】:

    您提出的解决方案已经足够好了。返回的 id 对您的应用来说是唯一的。

    使用返回给您的应用的 id 作为您应用中用户的标识符。

    查看此answer 的唯一 ID

    social_login插件留在这里

    // Import package
    import 'package:social_login/social_login.dart';
    
    // Instantiate it
     final socialLogin = SocialLogin();
    
    //Before calling any methods, set the configuration
    socialLogin.setConfig(SocialConfig(
          facebookAppId: FACEBOOK_APP_ID,
          googleWebClientId: GOOGLE_WEB_CLIENT_ID, /*In case a Google tokenId is needed*/
          twitterConsumer: TWITTER_CONSUMER_KEY,
          twitterSecret: TWITTER_CONSUMER_SECRET,
        ));
    
    // Get current logged user
     final FacebookUser facebookUser = await socialLogin.getCurrentFacebookUser();
     final GoogleUser googleUser = await socialLogin.getCurrentGoogleUser();
     final TwitterUser twitterUser = await socialLogin.getCurrentTwitterUser();
    
    //Log in social networks
     final FacebookUser facebookUser = await socialLogin.logInFacebookWithPermissions(FacebookPermissions.DEFAULT);
     final GoogleUser googleUser = await socialLogin.logInGoogle();
     final TwitterUser twitterUser = await socialLogin.logInTwitter();
    
    //Log out from social networks
     await socialLogin.logOutFacebook();
     await socialLogin.logOutGoogle();
     await socialLogin.logOutTwitter();
    

    【讨论】:

      【解决方案2】:

      通过使用 Firebase Authentication SDK (Official Guide) 的内置登录,您将能够获取不同平台的登录信息,例如 Google、Twitter、Facebook 甚至 Github。

      您无需编写自己的登录/注册代码,使用 Firebase 的正确功能可以轻松处理一切。

      之后您将获得类似这样的登录信息(这是来自电子邮件登录,但 Facebook、Google、Twitter 和 Github 可用):

      然后,您可以将标识符或用户 UID 链接到数据库中的信息。

      最后但同样重要的是,请记住为登录提供程序设置持久性设置,以便在用户关闭应用后保持登录。

      【讨论】:

        【解决方案3】:

        你应该把 Flutter 应用分成两部分:

        1. 应用程序的“主要”部分。它显示用户相关数据。
        2. 登录/注册部分。

        逻辑很简单。在应用程序启动时,您检查用户是否已通过身份验证。如果是,请将他导航到主屏幕。如果没有,请给他一个注册屏幕。以下是使用 Firebase 作为后端的方法:

        final currentUser = await FirebaseAuth.instance.currentUser();
        if (currentUser != null){
          // We're good: the user is authenticated.
          // Show him the main screen.
          Navigator.of(context).pushReplacement(MaterialPageRoute(
            builder: (context) => HomeScreen()
          ));
        } else {
          // The user is not logged in.
          // Show him the sign in/sign up screen.
          Navigator.of(context).pushReplacement(MaterialPageRoute(
            builder: (context) => SignInScreen()
          ));
        }
        

        【讨论】:

        • 如果我理解错误,请指教,我只需要外部登录提供商,例如 Google 或 Facebook,我的意思是我的应用程序中没有注册和内置用户登录。跨度>
        • 不需要外部身份验证提供程序(Google、Facebook 等)。但是你肯定需要一个后端
        【解决方案4】:

        也许这个例子满足你的需要:

        https://github.com/instaflutter/flutter-login-screen-firebase-auth-facebook-login

        如果你需要一些帮助理解,我可以帮助你!

        【讨论】:

          【解决方案5】:

          您应该使用令牌逻辑(由 google 和 facebook 使用)。

          您应该为每个用户生成一个令牌并将其存储在您的数据库中。通过这个令牌,你可以管理关于用户的每一件事。 当您调用 facebook authtinicating 时,它会给您一个特定用户的令牌。 当您再次将此令牌发送到 facebook 或 google 时,他们将回复用户的详细信息。 所以你可以像他们一样工作..为用户创建一个令牌并从你的数据库中调用它的信息..你可以存储从 facebook 响应的令牌并在将来匹配它.. 我回答的目的是去搜索令牌概念,因为它会给您带来很多好处。

          【讨论】:

          • JWT 中是否有任何用户大小限制,我的意思是如果我们有一个拥有 100 万用户的 Flutter 应用程序,我可以在这个 JWT 机制中实时管理这个用户吗,实际上我正在创建一个移动应用程序一个拥有 50 万用户的现有网站,所以我知道新用户的数量每天都在增加。
          【解决方案6】:

          这个想法很简单。用户使用 facebook/google/instagram 登录并从上述服务中获取 accessToken。此令牌必须与需要身份验证的每个请求一起发送。

          使用flutter storage保存token:https://pub.dev/packages/flutter_secure_storage

          我将向您发布我的一个 Flutter 应用程序示例,其中我使用 instagram 实现了登录。

          恢复下面的代码:

          • loginService.dart负责登录api调用并将token保存到存储中
          • main.dart 是应用程序的第一个视图。如果用户未登录,则会在此处显示 Login 小部件(LoginWidget 在 login.dart 中)。
          • login.dart 是登录页面的视图。有一个按钮从LoginService类调用函数

          代码如下:

          ~/lib/service/loginService.dart

          import 'dart:async';
          import 'dart:convert' as JSON;
          import 'package:http/http.dart' as http;
          import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
          import 'package:choose/model/User.dart';
          import 'package:flutter_secure_storage/flutter_secure_storage.dart';
          import 'package:choose/config.dart' as config;
          
          String apiBaseUrl = config.apiBase;
          String apiPort = config.port;
          
          class LoginService {
          
            String clientID;
            String secretID;
            String redirectURI;
            final FlutterSecureStorage storage = new FlutterSecureStorage();
            final String authKey = "token";
          
            LoginService(this.clientID, this.secretID, this.redirectURI);
          
            String get authenticationURI {
              return "https://api.instagram.com/oauth/authorize/?client_id=$clientID&redirect_uri=$redirectURI&response_type=code";
            }
          
            String get authorizationURI {
              return "https://api.instagram.com/oauth/access_token";
            }
          
            Future<User> authenticate() async {
              clean();
              FlutterWebviewPlugin _flutterWebviewPlugin = FlutterWebviewPlugin();
          
              // Stream<String> onCode = await _openServer();
              _flutterWebviewPlugin.launch(
                  authenticationURI
              );
          
              Completer<User> loginCompleter = Completer();
          
              _flutterWebviewPlugin.onStateChanged.listen((viewState) async {
                String url = viewState.url;
                int indexOfCode = url.lastIndexOf("?code=");
          
                if(url != null && indexOfCode >= 0 && viewState.type == WebViewState.finishLoad) {
                  String code = url.substring(url.indexOf('?code=') + 6, url.length);
          
                  http.Response userResponse = await http.get(
                    "${config.endpoints['getUserByCode']}?code=$code",
                  );
                  if(userResponse.statusCode == 200) {
                    User user = User.fromMap(JSON.jsonDecode(userResponse.body));
                    saveToken(user.token);
                    loginCompleter.complete(user);
                  } else {
                    loginCompleter.completeError("User not found");
                  }
                  _flutterWebviewPlugin.close();
                }
              });
          
          
          
              return loginCompleter.future;
            }
          
            void saveToken(token) async {
              storage.write(key: authKey, value: token);
            }
          
            void clean() async {
              storage.delete(key: authKey);
            }
          
            Future<String> getToken() async {
              return storage.read(key: authKey);
            }
          
            static Future<String> getStaticToken() async {
              FlutterSecureStorage storage = FlutterSecureStorage();
              return storage.read(key: "token");
            }
          
          }
          

          ~lib/main.dart

          import 'package:choose/friends.dart';
          import 'package:choose/model/User.dart';
          import 'package:flutter/material.dart';
          import 'package:choose/login.dart';
          import 'package:choose/service/loginService.dart';
          import 'package:web_socket_channel/io.dart';
          
          import 'feed.dart';
          import 'notification.dart';
          import 'newPost.dart';
          import 'config.dart' as config;
          
          void main() => runApp(MyApp());
          
          LoginService loginService = new LoginService(
            "71b818abd18043fb8b7c1833912b62ae",
            "3d9d6f87d2354085a74534c13bdda51f",
            config.endpoints['authorize'],
          );
          
          
          
          class MyApp extends StatelessWidget {
            // This widget is the root of your application.
            @override
            Widget build(BuildContext context) {
              return MaterialApp(
                title: 'Flutter Demo',
                theme: ThemeData(
                  // This is the theme of your application.
                  //
                  // Try running your application with "flutter run". You'll see the
                  // application has a blue toolbar. Then, without quitting the app, try
                  // changing the primarySwatch below to Colors.green and then invoke
                  // "hot reload" (press "r" in the console where you ran "flutter run",
                  // or simply save your changes to "hot reload" in a Flutter IDE).
                  // Notice that the counter didn't reset back to zero; the application
                  // is not restarted.
                  primarySwatch: Colors.blue,
                ),
                home: MyHomePage(title: 'Flutter Demo Home Page'),
                routes: {
                  '/feed': (context) => DefaultTabController(
                    length: 2,
                    child: FeedWidget()
                  ),
                  '/newpost': (context) => NewPost(),
                  '/notifications': (context) => NotificationWidget(
                    channel: IOWebSocketChannel.connect(config.websocketURI)
                  ),
                  '/friends': (context) => FriendsWidget(),
                }
          
              );
            }
          }
          
          class MyHomePage extends StatefulWidget {
            MyHomePage({Key key, this.title}) : super(key: key);
          
            // This widget is the home page of your application. It is stateful, meaning
            // that it has a State object (defined below) that contains fields that affect
            // how it looks.
          
            // This class is the configuration for the state. It holds the values (in this
            // case the title) provided by the parent (in this case the App widget) and
            // used by the build method of the State. Fields in a Widget subclass are
            // always marked "final".
          
            final String title;
          
            @override
            _MyHomePageState createState() => _MyHomePageState();
          }
          
          class _MyHomePageState extends State<MyHomePage> {
          
            User user;
            String label = 'Continue with Instagram';
          
            void openLoginPage() async {
          
              try {
                User _user = await loginService.authenticate();
                this.openPostPage();
              } catch(e) {
                this.setState(() {
                  label = 'Try Again';
                });
              }
          
            }
          
            void openPostPage() async {
              print(await loginService.getToken());
              print("token");
          
              Navigator.pushReplacementNamed(context, '/feed');
            }
          
            void actionDelegator() {
              if(user != null) {
                return openPostPage();
              } else {
                return openLoginPage();
              }
            }
          
            @override
            Widget build(BuildContext context) {
              // This method is rerun every time setState is called, for instance as done
              // by the _incrementCounter method above.
              //
              // The Flutter framework has been optimized to make rerunning build methods
              // fast, so that you can just rebuild anything that needs updating rather
              // than having to individually change instances of widgets.
              return Login(loginAction: actionDelegator, user: user, label: label);
            }
          }
          

          ~/lib/service/login.dart

          import 'package:flutter/material.dart';
          import 'package:font_awesome_flutter/font_awesome_flutter.dart';
          import 'package:choose/model/User.dart';
          
          class Login extends StatefulWidget {
          
            Login({this.loginAction, this.user, this.label});
          
            final loginAction;
            final User user;
            final String label;
          
            _Login createState() => _Login();
          
          }
          
          class _Login extends State<Login> {
          
            String imageURI = "https://www.travelcontinuously.com/wp-content/uploads/2018/04/empty-avatar.png";
          
            @override
            Widget build(BuildContext context) {
          
              if(widget.user != null && widget.user.profilePicture != '' ) {
                imageURI = widget.user.profilePicture;
              }
          
              return Container (
                color: Colors.green,
                child: Column (
                  crossAxisAlignment: CrossAxisAlignment.center,
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: <Widget>[
                    CircleAvatar (
                      backgroundColor: Colors.transparent,
                      radius: 50.0,
                      backgroundImage: NetworkImage(imageURI, scale: 2.0),
                    ),
          
                    Container(
                      padding: EdgeInsets.all(0.0),
                      margin: EdgeInsets.all(20.0),
                      color: Colors.transparent,
                      child: MaterialButton(
                        elevation: 5.0,
                        color: Color.fromRGBO(193, 53, 132, 1.0),
                        child: FlatButton.icon(
                          label: Text(widget.label, style: TextStyle(color: Color.fromRGBO(255,220,128, 1.0), fontWeight: FontWeight.w900, fontSize: 16.0)),
                          icon: Icon(FontAwesomeIcons.instagram, color: Color.fromRGBO(255,220,128, 1.0)),
                        ),
                        onPressed: () async {
                          widget.loginAction();
                        },
                      )
                    )
                  ],
                ),
              );
            }
          
          }
          

          【讨论】:

            【解决方案7】:

            (有人可能会觉得这很有帮助)。为了在颤振中轻松进行 oauth,请尝试使用签证 - https://github.com/e-oj/visa

            这是一个 Facebook auth 的示例(它还支持 google、twitch、discord 和 Github):

            import 'package:visa/auth-data.dart';
            import 'package:visa/fb.dart';
            
            class AuthPage extends StatelessWidget {
              @override
              Widget build(BuildContext context) {
                return Scaffold(
                  /// Simply Provide all the necessary credentials
                  body: FaceBookAuth().visa.authenticate(
                      clientID: '139732240983759',
                      redirectUri: 'https://www.e-oj.com/oauth',
                      scope: 'public_profile,email',
                      state: 'fbAuth',
                      onDone: done
                  )
                );
              }
            }
            

            以及“完成”回调:

            done(AuthData authData){
              print(authData);
            
              /// You can pass the [AuthData] object to a 
              /// post-authentication screen. It contaions 
              /// all the user and OAuth data collected during
              /// the authentication process. In this example,
              /// our post-authentication screen is "complete-profile".
              Navigator.pushReplacementNamed(
                  context, '/complete-profile', arguments: authData
              );
            }
            

            【讨论】:

              猜你喜欢
              • 2017-06-18
              • 2021-07-23
              • 1970-01-01
              • 2019-05-17
              • 2021-08-27
              • 2021-03-25
              • 1970-01-01
              • 1970-01-01
              • 2021-08-29
              相关资源
              最近更新 更多