[React Native] Tạo tính năng login với Firebase Authentication

16
Bài này thuộc phần 5 của 9 phần trong series React Native Training cho người mới

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.

Các bước tạo tính năng login với Firebase Authentication

Yêu cầu thư viện:

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:

React Native: Authentication

Để 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:

React Native: Authentication

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:

Xem tiếp các bài trong Series
Phần trước: [React Native] Props và State là gì? Khi nào thì sử dụng?Phần kế tiếp: 6 lỗi cần tránh để cải thiện hiệu năng ứng dụng React Native
Dịch vụ phát triển ứng dụng mobile giá rẻ - chất lượng

16
Bình luận. Cùng nhau thảo luận nhé!

avatar
  Theo dõi bình luận  
Mới nhất Cũ nhất Nhiều voted nhất
Thông báo
Dũng
Guest
Dũng

hay quá

Quân Nguyễn Châu
Member

Bạn ơi, cho mình hỏi cách kiểm tra vùng input ra sao luôn ạ ?

Nguyễn Quốc Huy
Guest
Nguyễn Quốc Huy

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

Nguyễn Quốc Huy
Guest
Nguyễn Quốc Huy

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 ạ

Quân Nguyễn Châu
Member

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 ạ ?