我对 Flutter 中的 Firestore 有疑问,因为我的应用程序陷入僵局,因为我有一个登录页面,其中包含用于登录的国家/地区、电子邮件和密码字段,我希望能够使用这 3 个字段对用户进行身份验证但是当我需要通过 Firestore 使用该国家/地区时,我无法检索它并且该字段用于验证,在我看来,要从 Firestore 检索字段,您无法通过 Firebase Auth 退出,因为您需要 currentUser 来访问该字段,我发现这很奇怪,我无法执行此逻辑,它首先检查用户是否经过身份验证,然后访问 Firebase 中的国家/地区字段并验证登录。有没有人做过类似的事情?
这是我的登录页面
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:whatsapp/Pages/reset_page.dart';
import 'package:whatsapp/Pages/sign_up.dart';
import 'package:whatsapp/auth/auth_page.dart';
import 'package:whatsapp/components/dropdown_button.dart';
import 'package:whatsapp/components/text_field.dart';
class LoginPage extends StatefulWidget {
const LoginPage({super.key});
@override
State<LoginPage> createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
final formKey = GlobalKey<FormState>();
String? name;
final TextEditingController _emailController = TextEditingController();
final TextEditingController _passwordController = TextEditingController();
bool obscureText = true;
String? _selectedCountry;
String? countryValue;
String? errorMessage;
String? errorMessageEmail;
String? errorMessagePassword;
String? errorMessageCountry;
final AuthPage _authPage = AuthPage();
_validateFields() async {
String email = _emailController.text;
String password = _passwordController.text;
if (_selectedCountry == 'United Kingdom') {
if (email.isNotEmpty && email.contains("@")) {
if (password.isNotEmpty) {
errorMessage = null;
errorMessageEmail = null;
errorMessagePassword = null;
signUserIn();
} else {
setState(() {
errorMessagePassword = 'Please enter your password';
});
}
} else {
setState(() {
errorMessageEmail = 'Please enter your E-mail ';
});
}
} else {
setState(() {
errorMessage = 'Please enter your country';
});
}
}
signUserIn() async {
String email = _emailController.text;
String password = _passwordController.text;
String? authResult = await _authPage.loginUser(
context, mounted, email, password);
setState(() {
errorMessage = authResult;
});
}
@override
Widget build(BuildContext context) {
final deviceWidth = MediaQuery.of(context).size.width;
final deviceHeight = MediaQuery.of(context).size.height;
return PopScope(
canPop: false,
child: SafeArea(
child: Scaffold(
backgroundColor: const Color(0xFF101d25),
appBar: AppBar(
automaticallyImplyLeading: false,
toolbarHeight: deviceHeight < 500
? deviceHeight * 0.15
: deviceHeight * 0.09,
centerTitle: true,
backgroundColor: const Color(0xFF101d25),
title: const Padding(
padding: EdgeInsets.only(top: 10),
child: Text('Verify your E-mail',
style: TextStyle(
color: Color(0xFF0ca886),
fontWeight: FontWeight.bold)),
),
actions: [
IconButton(
icon: const Icon(Icons.more_vert, color: Color(0xFF0ca886)),
onPressed: () {},
),
]),
body: SingleChildScrollView(
child: Center(
child: SizedBox(
height: deviceHeight < 500
? deviceHeight * 1.30
: deviceHeight * 0.80,
width: deviceWidth < 500
? deviceWidth * 0.80
: deviceWidth * 0.60,
child: Column(
//mainAxisAlignment: MainAxisAlignment.center,
children: [
const Padding(
padding: EdgeInsets.only(top: 10),
child: Text(
'WhatsApp will verify your registred\n e-mail. Enter your country, e-mail and password:',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 18, color: Colors.white),
),
),
SizedBox(height: deviceHeight * 0.05),
Form(
key: formKey,
child: Column(
children: [
CustomDropDownButton(
value: _selectedCountry,
onChanged: (newValue) {
_selectedCountry = newValue;
},
),
SizedBox(height: deviceHeight * 0.03),
CustomTextField(
labelText: 'E-mail',
keyboardType: TextInputType.emailAddress,
controller: _emailController,
onChanged: (value) {
if (value.isNotEmpty && value.contains("@")) {
errorMessageEmail = null;
}
},
errorText: errorMessageEmail,
),
SizedBox(height: deviceHeight * 0.02),
CustomTextField(
labelText: 'Password',
suffixIcon: GestureDetector(
onTap: () {
setState(() {
obscureText = !obscureText;
});
},
child: Padding(
padding: EdgeInsets.only(
top: deviceHeight < 500
? deviceHeight * 0.055
: deviceHeight * 0.025),
child: FaIcon(
obscureText
? FontAwesomeIcons.solidEye
: FontAwesomeIcons.solidEyeSlash,
color: const Color(0xFF0ca886),
size: 22),
),
),
keyboardType: TextInputType.visiblePassword,
obscureText: obscureText,
onChanged: (value) {
if (value.isNotEmpty) {
errorMessagePassword = null;
}
},
controller: _passwordController,
errorText: errorMessagePassword,
),
],
),
),
SizedBox(height: deviceHeight * 0.02),
RichText(
text: TextSpan(children: [
TextSpan(
text: 'Forgot your password?',
style: const TextStyle(
color: Colors.blue, fontSize: 15),
recognizer: TapGestureRecognizer()
..onTap = () {
//print('reset password');
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
const ResetPasswordPage()));
}),
]),
),
SizedBox(height: deviceHeight * 0.01),
Text(
errorMessage ??
'', // Exibe a mensagem de erro ou uma string vazia
style: const TextStyle(
color:
Colors.red, // Cor vermelha para indicar um erro
fontSize: 16,
),
),
SizedBox(height: deviceHeight * 0.01),
SizedBox(
height: deviceHeight < 500
? deviceHeight * 0.15
: deviceHeight * 0.06,
width: deviceWidth < 500
? deviceWidth * 0.68
: deviceWidth * 0.38,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
shape: BeveledRectangleBorder(
borderRadius: BorderRadius.circular(2),
),
backgroundColor: const Color(0xFF0ca886)),
onPressed: () {
_validateFields();
},
child: Padding(
padding: EdgeInsets.symmetric(
vertical: deviceWidth * 0.012),
child: const Text(
'Enter',
style: TextStyle(
color: Color(0xFF121a21), fontSize: 18),
),
),
),
),
Padding(
padding: EdgeInsets.only(top: deviceHeight * 0.02),
child: RichText(
text: TextSpan(children: [
const TextSpan(
text: "Don't have a account yet? ",
style:
TextStyle(color: Colors.white, fontSize: 14)),
TextSpan(
text: 'SignUp.',
style: const TextStyle(
color: Colors.blue,
fontSize: 14,
fontWeight: FontWeight.bold),
recognizer: TapGestureRecognizer()
..onTap = () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
const SignupPage()));
}),
])),
)
],
),
),
),
)),
),
);
}
}
这是我的 AuthPage
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:whatsapp/Pages/home.dart';
class AuthPage {
final _auth = FirebaseAuth.instance;
Future loginUser(
BuildContext context, bool mounted, String email, String password) async {
try {
// Exibe um CircularProgress antes de Autenticar
showCircularIndicator(context);
// await Future.delayed(const Duration(milliseconds: 5000));
await _auth.signInWithEmailAndPassword(email: email, password: password);
if (!mounted) return;
Navigator.pop(context);
_navigateToNextScreen(context);
// Pegar o usuario atual caso autenticado
/*
User? user = FirebaseAuth.instance.currentUser;
if (user != null) {
// Usuário está autenticado, agora você pode acessar o campo país
String? country = await getCountryForUser(user);
if (country != null) {
if (!mounted) return;
Navigator.pop(context);
_navigateToNextScreen(context);
} else{
return null;
}
// Faça o que precisa ser feito com o campo país
} else {
// Usuário não autenticado
print('Usuário não autenticado');
}
*/
// Se a autenticação for bem-sucedida, navegue para a próxima tela
} on FirebaseAuthException catch (e) {
// Esconde o circularIndicator
if (!mounted) return;
Navigator.pop(context);
// Se houver um erro, chame a função de retorno de erro
if (e.code == 'invalid-credential') {
return 'E-mail or Password invalid.';
} else if (e.code == 'too-many-requests') {
return 'Login failed, exceed requests try again soon.';
}
}
}
void _navigateToNextScreen(BuildContext context) {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const HomePage()),
);
}
void showCircularIndicator(BuildContext context) {
showDialog(
context: context,
builder: (BuildContext context) {
return const Center(
child: CircularProgressIndicator(color: Color(0xFF0ca886)),
);
});
}
Future<String?> getCountryForUser(User? user) async {
DocumentSnapshot<Map<String, dynamic>> snapshot = await FirebaseFirestore
.instance
.collection("users")
.doc(user?.uid)
.get();
if (snapshot.exists) {
return snapshot.data()?['country'];
} else {
return null;
}
}
}
我尝试检索 AuthPage 中的 Firestore 字段,但无法使用它在登录页面上进行验证,所以我陷入了困境,想了解是否有人可以帮助我。谢谢...
我正在尝试。
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:whatsapp/Pages/reset_page.dart';
import 'package:whatsapp/Pages/sign_up.dart';
import 'package:whatsapp/auth/auth_page.dart';
import 'package:whatsapp/components/dropdown_button.dart';
import 'package:whatsapp/components/text_field.dart';
class LoginPage extends StatefulWidget {
const LoginPage({super.key});
@override
State<LoginPage> createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
final formKey = GlobalKey<FormState>();
String? name;
final TextEditingController _emailController = TextEditingController();
final TextEditingController _passwordController = TextEditingController();
bool obscureText = true;
String? _selectedCountry;
String? countryValue;
String? errorMessage;
String? errorMessageEmail;
String? errorMessagePassword;
String? errorMessageCountry;
final AuthPage _authPage = AuthPage();
_validateFields() async {
String email = _emailController.text;
String password = _passwordController.text;
String? autResult =
await _authPage.loginUser(context, mounted, email, password);
User? user = FirebaseAuth.instance.currentUser;
countryValue = await _authPage.getCountryForUser(user);
if (_selectedCountry == countryValue) {
if (email.isNotEmpty && email.contains("@")) {
if (password.isNotEmpty) {
setState(() {
errorMessage = null;
});
} else {
setState(() {
errorMessagePassword = 'Please enter your password';
});
}
} else {
setState(() {
errorMessageEmail = 'Please enter your email';
});
}
} else {
setState(() {
errorMessage = 'Please enter your country';
});
}
setState(() {
errorMessage = autResult;
});
}
@override
Widget build(BuildContext context) {
final deviceWidth = MediaQuery.of(context).size.width;
final deviceHeight = MediaQuery.of(context).size.height;
return PopScope(
canPop: false,
child: SafeArea(
child: Scaffold(
backgroundColor: const Color(0xFF101d25),
appBar: AppBar(
automaticallyImplyLeading: false,
toolbarHeight: deviceHeight < 500
? deviceHeight * 0.15
: deviceHeight * 0.09,
centerTitle: true,
backgroundColor: const Color(0xFF101d25),
title: const Padding(
padding: EdgeInsets.only(top: 10),
child: Text('Verify your E-mail',
style: TextStyle(
color: Color(0xFF0ca886),
fontWeight: FontWeight.bold)),
),
actions: [
IconButton(
icon: const Icon(Icons.more_vert, color: Color(0xFF0ca886)),
onPressed: () {},
),
]),
body: SingleChildScrollView(
child: Center(
child: SizedBox(
height: deviceHeight < 500
? deviceHeight * 1.30
: deviceHeight * 0.80,
width: deviceWidth < 500
? deviceWidth * 0.80
: deviceWidth * 0.60,
child: Column(
//mainAxisAlignment: MainAxisAlignment.center,
children: [
const Padding(
padding: EdgeInsets.only(top: 10),
child: Text(
'WhatsApp will verify your registred\n e-mail. Enter your country, e-mail and password:',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 18, color: Colors.white),
),
),
SizedBox(height: deviceHeight * 0.05),
Form(
key: formKey,
child: Column(
children: [
CustomDropDownButton(
value: _selectedCountry,
onChanged: (newValue) {
setState(() {
_selectedCountry = newValue;
errorMessage = null;
});
},
validator: (newValue) {
if (newValue == null) {
errorMessage = 'Please enter your country';
}
return errorMessage;
},
),
SizedBox(height: deviceHeight * 0.03),
CustomTextField(
labelText: 'E-mail',
keyboardType: TextInputType.emailAddress,
controller: _emailController,
onChanged: (value) {
if (value.isNotEmpty && value.contains("@")) {
errorMessageEmail = null;
}
},
errorText: errorMessageEmail,
),
SizedBox(height: deviceHeight * 0.02),
CustomTextField(
labelText: 'Password',
suffixIcon: GestureDetector(
onTap: () {
setState(() {
obscureText = !obscureText;
});
},
child: Padding(
padding: EdgeInsets.only(
top: deviceHeight < 500
? deviceHeight * 0.055
: deviceHeight * 0.025),
child: FaIcon(
obscureText
? FontAwesomeIcons.solidEye
: FontAwesomeIcons.solidEyeSlash,
color: const Color(0xFF0ca886),
size: 22),
),
),
keyboardType: TextInputType.visiblePassword,
obscureText: obscureText,
onChanged: (value) {
if (value.isNotEmpty) {
errorMessagePassword = null;
}
},
controller: _passwordController,
errorText: errorMessagePassword,
),
],
),
),
SizedBox(height: deviceHeight * 0.02),
RichText(
text: TextSpan(children: [
TextSpan(
text: 'Forgot your password?',
style: const TextStyle(
color: Colors.blue, fontSize: 15),
recognizer: TapGestureRecognizer()
..onTap = () {
//print('reset password');
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
const ResetPasswordPage()));
}),
]),
),
SizedBox(height: deviceHeight * 0.01),
Text(
errorMessage ??
'', // Exibe a mensagem de erro ou uma string vazia
style: const TextStyle(
color:
Colors.red, // Cor vermelha para indicar um erro
fontSize: 16,
),
),
SizedBox(height: deviceHeight * 0.01),
SizedBox(
height: deviceHeight < 500
? deviceHeight * 0.15
: deviceHeight * 0.06,
width: deviceWidth < 500
? deviceWidth * 0.68
: deviceWidth * 0.38,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
shape: BeveledRectangleBorder(
borderRadius: BorderRadius.circular(2),
),
backgroundColor: const Color(0xFF0ca886)),
onPressed: () {
_validateFields();
},
child: Padding(
padding: EdgeInsets.symmetric(
vertical: deviceWidth * 0.012),
child: const Text(
'Enter',
style: TextStyle(
color: Color(0xFF121a21), fontSize: 18),
),
),
),
),
Padding(
padding: EdgeInsets.only(top: deviceHeight * 0.02),
child: RichText(
text: TextSpan(children: [
const TextSpan(
text: "Don't have a account yet? ",
style:
TextStyle(color: Colors.white, fontSize: 14)),
TextSpan(
text: 'SignUp.',
style: const TextStyle(
color: Colors.blue,
fontSize: 14,
fontWeight: FontWeight.bold),
recognizer: TapGestureRecognizer()
..onTap = () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
const SignupPage()));
}),
])),
)
],
),
),
),
)),
),
);
}
}