Medium - React Native & Firebase; Authentication

원문 - faraz amiruddin

Trend 파악을 Medium 기고문 요약 포스팅 - 리액트 네이티브와 파이어베이스; 인증

안녕하세요!👋🏽 저는 AdHawk의 소프트웨어 엔지니어인 Faraz 입니다. 이 가이드는 리액트 네이티브에서 파이어베이스의 인증을 사용하는 법에 대한 것입니다.

파이어베이스는 여러가지 굉장한 product를 제공해서 우리에게 모바일 앱을 빠르게 개발할 수 있도록 해줍니다. 거기에는 실시간 데이터베이스, 인증, 클라우드 Firestore, 클라우드 Functions, Crashlytics 등등이 있습니다.

우리는 간단히 이메일과 비밀번호로 로그인을 하는 간단한 흐름을 구성할 것입니다.

여기서 필요한 것은 FirebaseSDK와 리액트 네이티브 앱입니다만.. 고맙게도 Invertase의 관계자분들이 react-native-firebase를 만들어 주셨습니다. 이것은 리액트 네이티브와 파이어베이스를 연결해주는 멋진 오픈소스 프로젝트입니다.

Setting Up Our App

우리가 처음부터 시작하기 때문에 react-native-firebase에서 제공하는 basic starter kit으로 시작해야 합니다.

그들의 설명대로 따라해서 앱을 실행하시면 여러분은 준비가 된 것입니다.

Enable Email & Password Authentication in Firebase

다음은 우리가 만들려고 하는 흐름에 대한 다이어그램입니다.

A flow diagram of what we’re building

사용자에게 이메일과 비밀번호를 세트로 사용하도록 하려면 파이어베이스 콘솔에서 설정을 할 필요가 있습니다.

이것을 하기위해 여러분의 파이어베이스 프로젝트로가서 -> 인증 -> 로그인 메소로 들어가세요. Email/Password를 클릭해서 enable로 변경하시고 저장하세요. 여러분의 대시보드는 다음과 같을 것입니다.

Enabling email and password authentication

Creating our Screens

우리의 다이어그램을 살펴보면 우리의 앱은 4개의 화면이 있다는 것을 알게되실 겁니다. 그것들은 로딩, 회원가입, 로그인, 그리고 메인화면 입니다.

로딩 화면은 우리가 사용자의 인증 단계를 결정할 때까지 표시되며 회원가입 화면은 사용자가 계정을 만들 수 있는 화면이고 로그인 화면은 사용자가 로그인을 할 수 있는 곳이며 메인 화면은 우리의 앱에서 로그인한 사용자를 표시해줄 곳입니다.

우리는 앱 네비게이션에 react-navigation을 사용할 것입니다. 그래서 다음과 같이 네비게이터를 설정하고 우리의 화면들을 만듭시다.

yarn add react-navigation

이제 4개의 화면을 만들어봅시다.

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',
  }
})

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
  }
})

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
  }
})

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'
  }
})

이제 4개의 화면을 만들었으니까 App.js에 네비게이션을 넣읍시다.

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

우리가 앱을 실행시키면 Loading 화면과 ActivityIndicator가 계속해서 돌아가는 것이 보일 겁니다. 이것이 우리가 바란 것이며 우리가 사용자가 로그인 했는지 안했는지 구분할 필요가 있고 어떤 화면으로 보낼지 결정해야 하기 때문입니다.

사용자가 로그인 했다면 메인 화면으로 보내고 그렇지 않으면 회원가입 화면으로 보낼 겁니다.

Determining if a user is authenticated

우리는 파이어베이스를 사용해서 사용자의 인증상태를 결정할 수 있습니다. 로딩 화면에 사용자가 로그인 되었는지 아닌지 체크하는 것을 추가합시다.

// 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...

우리는 파이어베이스의 onAuthStateChanged 리스너를 사용해서 사용자의 현재 auth 상태를 감지합니다. 만약 로그인 했다면 메인화면으로 보내고 그렇지 않으면 회원가입 화면으로 보냅니다.

이제 우리가 로그인하지 않았으므로 로등화면은 잠깐만 표시되고 회원가입 화면으로 보낼 것입니다.

Signing a user up

우리는 새로운 사용자를 만들어서 그들이 로그인할 수 있도록 할 필요가 있습니다. 회원가입 화면으로 가서 회원가입처리 메소드를 연결합시다.

// 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...

사용자가 입력형식을 제출하면 우리는 createUserWithEmailAndPassword를 실행하고 그다음 메인화면으로 사용자를 보냅니다. 만약 에러가 있다면 캐치하여 화면에 표시합니다.

Displaying the current user on the Main screen

우리의 현재 구현에서 메인화면에서는 오직 로그인한 사용자가 보입니다. currentUser를 파이어베이스로 가져와서 그들의 이메일을 보여줄 겁니다. 메인 화면이 이것을 처리하도록 업데이트 합시다.

// 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...

이제 메인화면에서 우리는 사용자의 이메일 주소를 볼 수 있습니다. 만약 앱을 다시시작하면 우리는 자동적으로 메인화면으로 이동하게 됩니다. 왜냐면 이미 로그인되었기 때문이죠.

이제 이미 계정이 있는 사용자가 로그인을 하게하는 마지막 과정만 남았습니다.

Logging an already existing user in

로그인 화면을 업데이트해서 계정이 있는 사람들이 로그인 할 수 있도록 합시다.

// 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...

수고하셨습니다.

이제 여러분은 파이어베이스와 리액트네이티브로 간단한 인증 흐름을 경험하신 겁니다. 다음 링크에서 전체 소스코드를 확인하실 수 있습니다.

Summary

  • react-naitve-firebase를 사용해서 간단한 인증을 구현하는 예제

© 2019. All rights reserved.

Powered by Hydejack v8.1.1