在 Google Flutter 应用程序中管理社交用户详细信息

Posted

技术标签:

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

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

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

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

【问题讨论】:

【参考方案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 应用分成两部分:

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

逻辑很简单。在应用程序启动时,您检查用户是否已通过身份验证。如果是,请将他导航到主屏幕。如果没有,请给他一个注册屏幕。以下是使用 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 万用户的现有网站,所以我知道新用户的数量每天都在增加。 小妞***.com/questions/26033983/…【参考方案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
  );

【讨论】:

以上是关于在 Google Flutter 应用程序中管理社交用户详细信息的主要内容,如果未能解决你的问题,请参考以下文章

Flutter iOS 应用需要 Google 登录密码

好课分享: 智能社flutter从入门到精通+实战网易云音乐 百度云

云好课分享*智能社1flutter从入门到精通+实战网易云音乐…百度网盘分享#会员免费

如何在 Flutter 应用程序中获取 Google API 密钥

Flutter开发--Pub包管理

Java开发社招面试总结!java项目开发案例精粹光盘