Hôm nay, mình sẽ hướng dẫn các bạn cách xây dựng tính năng login bằng email và password sử dụng Firebase Authentication.
Firebase là một kiểu back-end service của google, cung cấp nhiều tính năng mạnh mẽ giúp việc phát triển ứng dụng mobile trở nên nhanh chóng hơn rất nhiều. Các tính năng chú ý có thể kể như: Realtime Database, Firebase Authentication, Cloud Firestore, Cloud Functions, Crashlytics…
💦 Tìm hiểu rõ hơn Firebase: Firebase là gì? Dịch vụ backend tuyệt vời của Google
Ở bài viết này, chúng ta sẽ sử dụng Firebase SDK và thư viện react-native-firebase. Đây là thư viện rất nổi tiếng để kết nối ứng dụng React Native với Firebase.
Nội dung chính của bài viết
Các bước tạo tính năng login với Firebase Authentication
Yêu cầu thư viện:
- FirebaseSDK
- Thư viện react-native-firebase
- Thư viện react-navigation
Cài đặt project
Để bắt đầu, chúng ta có thể sử dụng project mẫu được cung cấp sẵn bởi thư viện react-native-firebase. Các bạn download trên github và dùng được luôn. Nếu chưa thực sự rõ về cách dùng Github thì xem tại đây nhé.
Sau khi tải source code ở trên, bạn cài đặt dependencies và chạy thử ứng dụng. Nếu bạn gặp khó khăn thì có thể tham khảo bài viết hướng dẫn build ứng dụng React Native.
Sau khi cấu hình dự án thành công, chúng ta sẽ bắt tay thực hiện code phần chính của bài viết này.
Bật tính năng Email & Password Authentication trên Firebase
Mình minh họa workflow của tính năng xác thực login như hình bên dưới:
Để có thể sử dụng email và password cho tính năng login, chúng ta cần bật tính năng này trong firebase console trước.
Các bạn làm như sau:
Vào Firebase Project đã tạo trước đó → Authentication → Sign-in Method
Click vào mục Email/Password chọn Enable. Đại khái như hình bên dưới:
Xây dựng giao diện ứng dụng bằng React Native
Như workflow mà mình đã trình bày ở trên, ứng dụng của chúng ta sẽ cần phải có tối thiểu 4 màn hình:
- Loading: Màn hình này hiển thị khi chúng ta kết nối ứng dụng tới firebase khi chờ tiến hành authenticate (kiểu ProgressBar để người dùng biết là ứng dụng vẫn đang hoạt động mà không phải bị treo).
- SignUp: Màn hình đăng ký tài khoản mới bằng email và password.
- Login: Tất nhiên là cho người đã đăng kí có thể login.
- Home: Là màn hình sau khi người đã login thành công.
Để có thể di chuyển giữa các màn hình, chúng ta sẽ sử dụng thư viện react-navigation. Cài đặt thư viện này bằng lệnh:
yarn add react-navigation
Dưới đây là code cho từng màn hình mà mình đã nói ở trên:
Màn hình Loading (Loading.js)
// Loading.js import React from 'react' import { View, Text, ActivityIndicator, StyleSheet } from 'react-native' export default class Loading extends React.Component { render() { return ( <View style={styles.container}> <Text>Loading</Text> <ActivityIndicator size="large" /> </View> ) } } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', } })
Màn hình đăng ký (SignUp.js)
// SignUp.js import React from 'react' import { StyleSheet, Text, TextInput, View, Button } from 'react-native' export default class SignUp extends React.Component { state = { email: '', password: '', errorMessage: null } handleSignUp = () => { // TODO: Firebase stuff... console.log('handleSignUp') } render() { return ( <View style={styles.container}> <Text>Sign Up</Text> {this.state.errorMessage && <Text style={{ color: 'red' }}> {this.state.errorMessage} </Text>} <TextInput placeholder="Email" autoCapitalize="none" style={styles.textInput} onChangeText={email => this.setState({ email })} value={this.state.email} /> <TextInput secureTextEntry placeholder="Password" autoCapitalize="none" style={styles.textInput} onChangeText={password => this.setState({ password })} value={this.state.password} /> <Button title="Sign Up" onPress={this.handleSignUp} /> <Button title="Already have an account? Login" onPress={() => this.props.navigation.navigate('Login')} /> </View> ) } } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center' }, textInput: { height: 40, width: '90%', borderColor: 'gray', borderWidth: 1, marginTop: 8 } })
Màn hình đăng nhập (Login.js)
// Login.js import React from 'react' import { StyleSheet, Text, TextInput, View, Button } from 'react-native' export default class Login extends React.Component { state = { email: '', password: '', errorMessage: null } handleLogin = () => { // TODO: Firebase stuff... console.log('handleLogin') } render() { return ( <View style={styles.container}> <Text>Login</Text> {this.state.errorMessage && <Text style={{ color: 'red' }}> {this.state.errorMessage} </Text>} <TextInput style={styles.textInput} autoCapitalize="none" placeholder="Email" onChangeText={email => this.setState({ email })} value={this.state.email} /> <TextInput secureTextEntry style={styles.textInput} autoCapitalize="none" placeholder="Password" onChangeText={password => this.setState({ password })} value={this.state.password} /> <Button title="Login" onPress={this.handleLogin} /> <Button title="Don't have an account? Sign Up" onPress={() => this.props.navigation.navigate('SignUp')} /> </View> ) } } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center' }, textInput: { height: 40, width: '90%', borderColor: 'gray', borderWidth: 1, marginTop: 8 } })
Màn hình chính (Main.js)
// Main.js import React from 'react' import { StyleSheet, Platform, Image, Text, View } from 'react-native' export default class Main extends React.Component { state = { currentUser: null } render() { const { currentUser } = this.state return ( <View style={styles.container}> <Text> Hi {currentUser && currentUser.email}! </Text> </View> ) } } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center' } })
Sau khi hoàn thành giao diện các màn hình, chúng ta kết nối chúng vào App.js để có thể navigate.
//App.js import React from 'react' import { StyleSheet, Platform, Image, Text, View } from 'react-native' import { SwitchNavigator } from 'react-navigation' // import the different screens import Loading from './Loading' import SignUp from './SignUp' import Login from './Login' import Main from './Main' // create our app's navigation stack const App = SwitchNavigator( { Loading, SignUp, Login, Main }, { initialRouteName: 'Loading' } ) export default App
Ok, bạn thử chạy ứng dụng xem thế nào? Bạn sẽ thấy màn hình Loading quay mãi mãi. Hiện tại thì ứng dụng của mình mới chỉ đến được đây thôi.
Chúng ta sẽ tiến hành code phần authenticate ngay bên dưới để khi người dùng nhập email và password thành công thì đưa User sang màn hình Home.
💦 Đừng bỏ lỡ: Đăng nhập không cần mật khẩu với Account Kit Android
Xác định một User đã xác thực rồi hay chưa?
Chúng ta có thể sử dụng Firebase để xác định trạng thái xác thực của user. Chỉ đơn giản là thêm một hàm kiểm tra trạng thái xem user đã login rồi hay chưa ở màn hình Loading.
// Loading.js // Omitted other imports... import firebase from 'react-native-firebase' export default class Loading extends React.Component { componentDidMount() { firebase.auth().onAuthStateChanged(user => { this.props.navigation.navigate(user ? 'Main' : 'SignUp') }) } // Omitted the rest of the file...
Ở đoạn code trên, chúng ta sử dụng onAuthStateChanged
listener để lấy trạng thái xác thực hiện tại của user. Nếu user này đã xác thực (authenticated), đưa user này vào màn hình Main. Còn không, user này sẽ được chuyển sang màn hình Đăng ký để tiến hành tạo tài khoản mới.
Đăng kí tài khoản mới
Để có thể đăng kí tài khoản mới, chúng ta sử dụng hàm handleSignUp
// SignUp.js // Omitted other imports... import firebase from 'react-native-firebase' export default class SignUp extends React.Component { state = { email: '', password: '', errorMessage: null } handleSignUp = () => { firebase .auth() .createUserWithEmailAndPassword(this.state.email, this.state.password) .then(() => this.props.navigation.navigate('Main')) .catch(error => this.setState({ errorMessage: error.message })) } // Omitted the rest of the file...
Khi người dùng đăng ký thông tin và thành công, chúng ta sẽ đưa người dùng sang màn hình Home.
Còn nếu bị lỗi (ví dụ: mất kết nối internet, lỗi dữ liệu…), hiển thị thông báo ra màn hình.
Hiển thị thông tin đăng nhập ở màn hình Home
Với implementation hiện tại, chúng ta chỉ thấy màn hình Home trắng bóc sau khi user đã logined.
Để đỡ nhàm chán, chúng ta sẽ hiển thị thông tin của họ (ở trường hợp này là Email). Tất nhiên, thông tin này sẽ được lấy từ firebase.
// Main.js // Omitted other imports... import firebase from 'react-native-firebase' export default class Main extends React.Component { state = { currentUser: null } componentDidMount() { const { currentUser } = firebase.auth() this.setState({ currentUser }) } // Omitted the rest of the file...
Xong đoạn code trên, màn hình Home đã hiển thị địa chỉ email của người dùng.
Nếu bạn refresh lại ứng dụng, lúc này ứng dụng không cần phải bắt người dùng đăng nhập lại nữa.
Bước cuối cùng của bài hướng dẫn này là tính năng login cho người đã đăng kí.
Thực hiện Login từ user đã đăng ký
Để tạo màn hình login này cũng đơn giản thôi, chúng ta sử dụng hàm handleLogin
:
// Login.js // Omitted other imports... import firebase from 'react-native-firebase' export default class Login extends React.Component { state = { email: '', password: '', errorMessage: null } handleLogin = () => { const { email, pasword } = this.state firebase .auth() .signInWithEmailAndPassword(email, password) .then(() => this.props.navigation.navigate('Main')) .catch(error => this.setState({ errorMessage: error.message })) } // Omitted the rest of the file...
Đã xong!
Như vậy là chúng ta đã hoàn thành đầy đủ các tính năng cần thiết cho một user: Đăng ký, đăng nhập, lấy thông tin email. Bạn có thể download full source code của bài viết tại đây:
Ứng dụng của bạn có sử dụng đến tính năng login này không? Mình rất muốn biết ý kiến của bạn về bài viết này. Hãy để lại comment bên dưới nhé.
💦 Đọc thêm hướng dẫn khác về React Native:
hay quá
Bạn ơi, cho mình hỏi cách kiểm tra vùng input ra sao luôn ạ ?
Mình không hiểu ý bạn lắm 🙁
Ý mình là khi điền form, giả sử mình bỏ trống email thì form phải báo thông điệp là “email không hợp lệ”, khi giá trị mình điền không phải là email thì phải báo thông diệp là “email không hợp lệ”.
À, mình hiểu rồi.
bạn thử dùng thư viện này nhé: https://www.npmjs.com/package/react-native-form-validator
thư viện này mình đã dùng thử rồi, khi thử nhập sai, nó rơi vào màn hình lỗi rồi disable input luôn. Bạn có thể cung cấp thêm được ko ạ ? Nhập sai thì cho phép nhập lại lần nữa là ok
dùng formilk va yup nha
Cho mình hỏi thêm tí nữa, mình không thấy chỗ bạn config cái firebase đâu hết trơn, bạn để nó trong file nào vậy :)) Gỉa như mình muốn chuyển về firebase của mình thì làm như nào
Hi Huy,
Bạn tạo project trên Firebase console rồi sau đó download file google-services.json và đặt vào thư mục ngang với thư mục app của dự án của bạn là được. Như vậy, dự án của bạn sẽ trỏ sang tài khoản firebase của bạn nhé
Mình có thêm một lỗi nữa, không biết có phải do phiên bản của các package hay không nhưng sau khi BUILD SUCCESSED rồi nhưng ứng dụng vẫn không thể chạy.
Khi mình mở máy điện thoại lên thì nó báo là “PhoneAuth không khởi động một vài lần, Khôi phục nó bằng cách xóa lịch sử” không biết lỗi gì ạ
cho em hỏi là khi down source code về làm thế nào để chạy trên android ạ (react-native run-android) thì nó download cái file(Downloading https://services.gradle.org/distributions/gradle-2.14.1-all.zip) và đứng lại sau khi giải nén. cho em hỏi bị lỗi gì vậy ạ
bạn chạy bằng gõ lệnh hay import vào Android Studio?
minh chay bang go lenh trong Cmd( Run as Admin)
Bạn thử thay đổi link gradle trong file gradle-wrapper.properties (trong folder “gradle/wrapper”) thành: distributionUrl=file:/tmp/gradle-2.14.1-all.zip
Nó sẽ bắt download mỗi khi bạn run command nữa. Hi vọng là fix đc lỗi cho bạn.
Cho mình hỏi cách đăng nhập bằng số điện thoại và mật khẩu sử dụng firebase ra sao ạ ?
Bạn thử tham khảo hướng dẫn chi tiết của mình tại đây nhé
https://vntalking.com/dang-nhap-khong-can-mat-khau-android.html