在 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从入门到精通+实战网易云音乐 百度云
云好课分享*智能社1flutter从入门到精通+实战网易云音乐…百度网盘分享#会员免费