使用Firebase电话验证的一键式登录/注册页面

huangapple go评论90阅读模式
英文:

Using One Page Login/Registration with Firebase Phone Authentication

问题

在您提供的Flutter代码中,您已经成功完成了电话验证系统。现在,您想要为新用户和老用户分别创建不同的机制。

以下是修改后的代码,以实现您所描述的功能:

import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:pinput/pinput.dart';

import '../utils/route.dart';

class SignUpPage extends StatefulWidget {
  const SignUpPage({Key? key}) : super(key: key);

  @override
  _SignUpPageState createState() => _SignUpPageState();
}

class _SignUpPageState extends State<SignUpPage> {
  final FirebaseAuth auth = FirebaseAuth.instance;
  String countryCode = "+880";
  String phoneNumber = "";
  String otpCode = "";
  String phoneVerificationId = "";

  @override
  void initState() {
    super.initState();
  }

  signUp(String phoneNumber) async {
    FirebaseAuth.instance.verifyPhoneNumber(
      phoneNumber: phoneNumber,
      verificationCompleted: (PhoneAuthCredential credential) {
        // Handle auto-verification for existing users.
        signInWithCredential(credential);
      },
      verificationFailed: (FirebaseAuthException e) {
        print("Verification Failed: ${e.message}");
      },
      codeSent: (String verificationId, int? resendToken) {
        phoneVerificationId = verificationId;
      },
      codeAutoRetrievalTimeout: (String verificationId) {},
    );
  }

  // Function to sign in with phone credential
  signInWithCredential(PhoneAuthCredential credential) async {
    try {
      final currentUser = await auth.signInWithCredential(credential);

      if (currentUser.user != null) {
        // User is successfully authenticated
        // Check if this is a new user or an existing user
        final user = currentUser.user!;
        if (user.metadata.creationTime == user.metadata.lastSignInTime) {
          // This is a new user, redirect to registration page
          Navigator.pushNamed(context, MyRoutes.userInformationRoute);
        } else {
          // This is an existing user, redirect to home page
          Navigator.pushNamed(context, MyRoutes.homeRoute);
        }
      }
    } catch (e) {
      print("Sign In Error: $e");
    }
  }

  // ... Rest of your code ...

  @override
  Widget build(BuildContext context) {
    // ... Rest of your build method ...
  }
}

在修改后的代码中,我添加了一个新的函数signInWithCredential,用于在通过电话凭据进行身份验证后处理用户登录。在该函数中,我首先检查用户是否是新用户还是现有用户,然后分别将他们重定向到不同的页面(注册页面或主页)。这将实现您所需的新用户和老用户分别的机制。

英文:

So, I have Witten some code in flutter. here I asking the phone number to generate OTP and after passing the OTP it successfully login. but here I need some changes. When even I submitted the OTP then its check the number is already in the firebase phone authentication console. if its already been their it will just show me the home page. otherwise if the number is not exist then it goes to a UserInformation page where user need to give some simple information then after continue it will show the home page. in a sense I need a one page login registration panel by using only phone number.
here is my flutter code.

import &#39;package:firebase_auth/firebase_auth.dart&#39;;
import &#39;package:flutter/material.dart&#39;;
import &#39;package:flutter/src/widgets/framework.dart&#39;;
import &#39;package:flutter/src/widgets/placeholder.dart&#39;;
import &#39;package:pinput/pinput.dart&#39;;
import &#39;../utils/route.dart&#39;;
class SignUpPage extends StatefulWidget {
const SignUpPage({super.key});
@override
State&lt;SignUpPage&gt; createState() =&gt; _SignUpPageState();
}
class _SignUpPageState extends State&lt;SignUpPage&gt; {
final FirebaseAuth auth = FirebaseAuth.instance;
// bool _obscureText = true;
String countryCode = &quot;+880&quot;;
String phoneNumber = &quot;&quot;;
String otpCode = &quot;&quot;;
String phoneVerificationId = &quot;&quot;;
@override
void initState() {
// TODO: implement initState
super.initState();
}
signUp(String phoneNumber) async {
FirebaseAuth.instance.verifyPhoneNumber(
phoneNumber: phoneNumber,
verificationCompleted: (PhoneAuthCredential credential) {},
verificationFailed: (FirebaseAuthException e) {},
codeSent: (String verificationId, int? resendToken) {
phoneVerificationId = verificationId;
},
codeAutoRetrievalTimeout: (String verificationId) {},
);
}
final defaultPinTheme = PinTheme(
width: 56,
height: 56,
textStyle: TextStyle(
fontSize: 20,
color: Color.fromRGBO(30, 60, 87, 1),
fontWeight: FontWeight.w600),
decoration: BoxDecoration(
border: Border.all(color: Color(0xFF1818B4)),
borderRadius: BorderRadius.circular(20),
),
);
@override
Widget build(BuildContext context) {
final focusedPinTheme = defaultPinTheme.copyDecorationWith(
border: Border.all(color: Color(0xFF1818B4)),
borderRadius: BorderRadius.circular(15),
);
final submittedPinTheme = defaultPinTheme.copyWith(
decoration: defaultPinTheme.decoration?.copyWith(
color: Color.fromRGBO(234, 239, 243, 1),
),
);
return Scaffold(
backgroundColor: Color(0xFF1818B4),
body: Column(
children: [
Column(children: [
Padding(
padding: const EdgeInsets.only(top: 70.0),
child: Container(
height: 200,
alignment: Alignment.center,
child: Image.asset(
&#39;assets/images/we_serve.jpg&#39;,
),
),
),
SizedBox(
height: 10,
),
Text(
&#39;WHERE SERVICE MEETS EXCELLENCE&#39;,
style: TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
]),
SizedBox(
height: 50,
),
Padding(
padding: const EdgeInsets.only(left: 22, bottom: 10),
child: Align(
alignment: Alignment.centerLeft,
child: Text(
&quot;Please Enter Your Mobile Number&quot;,
style: TextStyle(color: Colors.white),
textAlign: TextAlign.left,
),
),
),
Padding(
padding: const EdgeInsets.only(left: 20, right: 20),
child: Row(
children: [
Expanded(
flex: 2,
child: TextFormField(
enabled: false,
decoration: InputDecoration(
filled: true,
fillColor: Colors.white,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10)),
hintText: &quot;  +880&quot;,
hintStyle: TextStyle(
color: Color.fromARGB(255, 64, 63, 63),
fontWeight: FontWeight.bold),
),
),
),
SizedBox(width: 5),
Flexible(
flex: 7,
child: TextField(
// controller: _phoneController,
onChanged: (value) =&gt; {
phoneNumber = countryCode + value,
},
keyboardType: TextInputType.phone,
decoration: InputDecoration(
filled: true,
fillColor: Colors.white,
// labelText: &#39;Mobile Number&#39;,
hintText: &quot;Mobile Number&quot;,
hintStyle: TextStyle(color: Colors.grey),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0),
)),
),
),
],
),
),
SizedBox(
height: 30,
),
ElevatedButton(
onPressed: () async {
signUp(phoneNumber);
showDialog(
barrierColor: Colors.grey.withOpacity(.7),
context: context,
builder: (BuildContext context) {
return AlertDialog(
titlePadding: const EdgeInsets.all(0),
elevation: 8,
titleTextStyle: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 20,
color: Colors.white),
shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(20),
),
title: Container(
color: Color(0xFF1818B4),
child: Center(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Text(&#39;Verification Code&#39;),
)),
),
content: Container(
height: 120,
child: Form(
// key: _formkey,
child: Column(
children: [
SizedBox(height: 20),
Center(
child: Text(&quot;Please Enter Your 6-digit OTP&quot;)),
SizedBox(height: 20),
Pinput(
defaultPinTheme: defaultPinTheme,
focusedPinTheme: focusedPinTheme,
submittedPinTheme: submittedPinTheme,
pinputAutovalidateMode:
PinputAutovalidateMode.onSubmit,
length: 6,
showCursor: true,
onChanged: (value) =&gt; {
otpCode = value,
},
)
],
),
),
),
actions: [
Center(
child: ElevatedButton(
onPressed: () async {
try {
final currentUser =
FirebaseAuth.instance.currentUser;
print(currentUser?.uid);
PhoneAuthCredential credential =
PhoneAuthProvider.credential(
verificationId: phoneVerificationId,
smsCode: otpCode);
print(credential);
await auth.signInWithCredential(credential);
Navigator.pushNamed(context, MyRoutes.homeRoute);
} catch (e) {
print(&quot;Wrong OTP&quot;);
}
},
style: ElevatedButton.styleFrom(
backgroundColor: Color(0xFFFFE001),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20))),
child: Padding(
padding: const EdgeInsets.only(
left: 40, right: 40, top: 10, bottom: 10),
child: Text(
&#39;Confirm&#39;,
style: TextStyle(
fontSize: 24,
// color: Color(0xFF1818B4),
color: Colors.black),
),
),
),
),
SizedBox(
height: 40,
)
],
);
},
);
},
style: ElevatedButton.styleFrom(
backgroundColor: Color(0xFFFFE001),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20))),
child: Padding(
padding: const EdgeInsets.only(
left: 70, right: 70, top: 10, bottom: 10),
child: Text(
&#39;Continue&#39;,
style: TextStyle(
fontSize: 24,
// color: Color(0xFF1818B4),
color: Colors.black),
),
),
),
Spacer(),
Padding(
padding: const EdgeInsets.only(bottom: 20),
child: GestureDetector(
onTap: () {
// Navigator.pushNamed(context, MyRoutes.homeRoute);
},
child: Text(
&#39;Contact Us&#39;,
style: TextStyle(
fontSize: 24,
color: Color(0xFF808080),
),
),
),
),
],
),
);
}
}

I have completed the phone verification system successfully. Now want to separate mechanism for new user and old user.

答案1

得分: 0

当OTP验证完成后,您可以检查一个条件。在这里,您可以使用Firebase Firestore或实时数据库来检查用户号码是否存在。如果用户号码不存在,那么用户将被重定向到注册流程,用户填写完详细信息并提交详细信息的同时,将用户电话号码存储到Firebase数据库中。

并且每次OTP验证完成后都要检查用户电话是否存在,根据情况进行路由。

如果您使用Firebase Firestore,可以像这样实现它:

您可以创建一个名为users的表:

要检查用户是否存在,可以像这样做:

Future<bool> isUserExist(String phoneNumber) async {
    final usersCollection = FirebaseFirestore.instance.collection('users');
    final querySnapshot = await usersCollection
        .where('phoneNumber', isEqualTo: phoneNumber)
        .get();

    return querySnapshot.docs.isNotEmpty;
}

在OTP验证后路由用户:

routeUser(phoneNumber) async {
    final userExists = await isUserExist(phoneNumber);

    if (userExists) {
      Navigator.pushReplacement(
        context,
        MaterialPageRoute(builder: (context) => HomePage()),
      );
    } else {
      Navigator.pushReplacement(
        context,
        MaterialPageRoute(builder: (context) => UserInformationPage()),
      );
    }
}

在注册用户信息提交时创建用户:

Future<void> createUser(String phoneNumber) async {
    final usersCollection = FirebaseFirestore.instance.collection('users');

    // 设置用户电话号码为ID的文档
    await usersCollection.doc(phoneNumber).set({
      'phoneNumber': phoneNumber,
      // 如果需要存储其他数据,也可以存储它们
    });
}

流程:
使用Firebase电话验证的一键式登录/注册页面

英文:

I have an opinion for your requirement. I give you a suggestion according to Firebase.

When Otp verification completed then you can check a one condition. Where you can use Firebase Firestore or Realtime database to check user number exists or not. If user number not exist then user will be redirected to Register flow and user once fill the details and submit the details at that time store user phonenumber into Firebase database.

And every after Otp verification complete check condition if user phone exists or not according to that make Routing.

If you use Firebase Firestore so you can achieve it like this:

You can create a table for users:

For check user exist or not so you can do it like this:

Future&lt;bool&gt; isUserExist(String phoneNumber) async {
final usersCollection = FirebaseFirestore.instance.collection(&#39;users&#39;);
final querySnapshot = await usersCollection
.where(&#39;phoneNumber&#39;, isEqualTo: phoneNumber)
.get();
return querySnapshot.docs.isNotEmpty;
}

User routing after Otp verification:

routeUser(phoneNumber) async {
final userExists = await isUserExist(phoneNumber);
if (userExists) {
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) =&gt; HomePage()),
);
} else {
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) =&gt; UserInformationPage()),
);
}
}

For creating user while Register user info submission:

Future&lt;void&gt; createUser(String phoneNumber) async {
final usersCollection = FirebaseFirestore.instance.collection(&#39;users&#39;);
// Set the document with the user phone number as the ID
await usersCollection.doc(phoneNumber).set({
&#39;phoneNumber&#39;: phoneNumber,
// If need to store others data so you can also store them
});
}

Flow:
使用Firebase电话验证的一键式登录/注册页面

huangapple
  • 本文由 发表于 2023年8月10日 15:05:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/76873332.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定