재우니의 블로그

Expo - React Native 와 Firebase 활용하여 email authentication(인증) 구현하기

 

 

소개

처음부터 자신만의 인증을 작성하고 싶지 않다면 타사 솔루션에 도달하고 싶을 것입니다. 다행스럽게도 Firebase에는 React Native와 매우 잘 작동하는 훌륭한 인증 서비스가 있습니다.

이 자습서에서는 등록, 로그인 및 암호 재설정 흐름을 구현하는 방법을 포함하여 기존의 이메일 기반 인증으로 설정하는 방법을 보여줍니다.

참고: 이 가이드에서는 Firebase 자바스크립트 SDK 버전 9를 사용합니다 .

즉시 사용 가능한 Firebase 및 Firebase 인증 설정을 시작하려면 포털 - 내 무료 React Native 로그인 템플릿을 확인하세요 .

 

Firebase란 무엇인가요?

Firebase는 본질적으로 서비스로서의 백엔드입니다. Firebase는 인증, 저장 및 실시간 데이터베이스를 포함하여 모바일 애플리케이션과 함께 사용하려는 대부분의 백엔드 기능을 제공합니다.

 

Firebase 설치

React Native로 Firebase를 설정하는 방법에 대한 지침은 내 빠른 가이드를 확인하십시오 .

 

Firebase로 이메일 인증 구성

빠른 가이드 에 따라 Firebase 구성을 설정했으면 인증을 사용해야 하는 모든 구성 요소 파일에서 인증 인스턴스를 가져옵니다.

 

import { auth } from './yourFirebaseConfig';

 

이제 Firebase 프로젝트에 대한 이메일 인증을 활성화하기만 하면 됩니다. Firebase 콘솔을 열고 인증 탭으로 이동합니다.

화면 상단의 로그인 방법 탭을 클릭합니다.

 

 

그러면 활성화된 인증 방법 목록이 나타납니다. 새 공급자 추가 버튼을 클릭합니다.

 

 

그러면 사용 가능한 인증 방법 목록이 표시됩니다. 이메일/비밀번호 옵션을 클릭하여 구성 양식을 엽니다.

 

 

그러면 사용 가능한 인증 방법 목록이 표시됩니다. 이메일/비밀번호 옵션을 클릭하여 구성 양식을 엽니다.

 

 

그러면 활성화 토글이 표시됩니다. 활성화로 설정하고 저장을 클릭하면 이제 이메일 기반 인증을 구현할 준비가 된 것입니다!

 

 

auth object 설정

import { initializeApp } from 'firebase/app';
import { getAuth } from 'firebase/auth';

// Initialize Firebase
const firebaseConfig = {
  apiKey: 'YOUR_FIREBASE_API_KEY',
  authDomain: 'YOUR_FIREBASE_AUTH_DOMAIN',
  databaseURL: 'YOUR_FIREBASE_DATABASE_URL',
  projectId: 'YOUR_FIREBASE_PROJECT_ID',
  storageBucket: 'YOUR_FIREBASE_STORAGE_BUCKET',
  messagingSenderId: 'YOUR_FIREBASE_MESSAGING_SENDER_ID',
  appId: 'YOUR_FIREBASE_APP_ID',
  measurementId: 'YOUR_FIREBASE_MEASUREMENT_ID',
};

const app = initializeApp(firebaseConfig);

export const auth = getAuth();
export default app;

 

사용자가 로그인했는지 확인

 

먼저 onAuthStateChanged라는 Firebase 메서드를 사용하여 사용자가 로그인했는지 확인합니다. 지금은 로그인 및 가입 양식이 없기 때문에 아무 작업도 수행하지 않지만 결국 이것이 라우팅의 기초가 될 것입니다.

 

onAuthStateChanged(auth, (user) => {
  if (user) {
    // user is logged in
  } else {
    // user is not logged in
  }
});

 

기본 앱 구성 요소를 만들고 이 함수에 의해 값이 설정될 loggedIn 상태를 추가해 보겠습니다.

import React, { useState } from 'react';
import { View, Text } from 'react-native';
import { onAuthStateChanged } from 'firebase/auth';

import { auth } from './firebase';

export default function App() {
  const [loggedIn, setLoggedIn] = useState(false);

  onAuthStateChanged(auth, (user) => {
    if (user) {
      setLoggedIn(true);
    } else {
      setLoggedIn(false);
    }
  });

  return (
    <View>
      <Text>App</Text>
    </View>
  );
}

 

이제 이 loggingIn 값을 사용하여 사용자가 로그인했는지 여부에 따라 콘텐츠를 조건부로 렌더링할 수 있습니다.

 

 

로그인 페이지 추가
 

 

로그아웃 버튼이 포함된 로그인 사용자를 위한 기본 페이지를 추가해 보겠습니다. (이 튜토리얼을 위해 App 구성 요소와 동일한 파일에 만들 예정이지만 별도의 파일을 자유롭게 만들 수 있습니다.)
 
function LoggedIn() {
  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Text>Logged in</Text>
    </View>
  );
}
 

파일 상단의 Firebase에서 signOut 메서드를 가져옵니다.

import { signOut } from 'firebase/auth';

 

그런 다음 사용자를 로그아웃시키는 LoginIn 구성 요소에 메서드를 추가할 수 있습니다.

import React, { useState } from 'react';
import { View, Text, Button } from 'react-native';
import { onAuthStateChanged, signOut } from 'firebase/auth';

import { auth } from './firebase';

function LoggedIn() {
  const logout = async () => {
    try {
      await signOut(auth);
    } catch (e) {
      console.error(e);
    }
  };

  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Text>Logged in</Text>
    </View>
  );
}

export default function App() {
  //
}
 
그런 다음 이 메서드를 호출하는 로그아웃 버튼을 만들 수 있습니다.
import React, { useState } from 'react';
import { View, Text, Button } from 'react-native';
import { onAuthStateChanged, signOut } from 'firebase/auth';

import { auth } from './firebase';

function LoggedIn() {
  const logout = async () => {
    try {
      await signOut(auth);
    } catch (e) {
      console.error(e);
    }
  };

  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Text>Logged in</Text>
      <Button title="Log out" onPress={logout} />
    </View>
  );
}

export default function App() {
  //
}

 

그러면 사용자가 로그아웃되고 App 구성 요소의 onAuthStateChanged 메서드가 반환된 사용자 없이 실행됩니다. 즉, 이제 loggingIn 상태가 false가 됩니다. 물론 로그인하거나 사용자를 만들 수 있는 방법이 없기 때문에 실제로 사용자를 로그아웃할 수는 없습니다. 가입 양식을 만들어서 해결해 보겠습니다.
 

기본 라우팅 설정

 

최종적으로 가입 양식을 포함할 기본 구성 요소를 추가하여 시작하겠습니다.
function Signup() {
  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Text>Sign up</Text>
    </View>
  );
}

 

이제 사용자가 로그인했는지 여부에 따라 앱 구성 요소에 몇 가지 기본 라우팅을 추가해 보겠습니다. 지금은 LoggedIn 구성 요소와 Signup 구성 요소의 두 화면만 있습니다. 우리는 getScreen 메서드를 만든 다음 App 구성 요소의 자식으로 호출합니다. loggingIn 상태가 참이면 LoggedIn 구성 요소를 반환합니다. false이면 Signup 구성 요소를 반환합니다.

 

export default function App() {
  const [loggedIn, setLoggedIn] = useState(false);

  onAuthStateChanged(auth, (user) => {
    if (user) {
      setLoggedIn(true);
    } else {
      setLoggedIn(false);
    }
  });

  const getScreen = () => {
    if (loggedIn) return <LoggedIn />;
    return <Signup />;
  };

  return <View style={{ flex: 1 }}>{getScreen()}</View>;
}

 

가입 양식 작성

 

이제 라우팅 설정이 완료되어 가입 양식을 만들 수 있습니다. 네 가지 상태 값을 만드는 것으로 시작합니다. 하나는 사용자 이름, 하나는 비밀번호, 다른 하나는 비밀번호 확인용입니다. 그리고 다른 하나는 Firebase가 반환하는 오류 메시지를 보관하여 사용자에게 표시할 수 있도록 하는 것입니다.
function Signup() {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [confirmPassword, setConfirmPassword] = useState('');
  const [error, setError] = useState(null);

  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Text>Sign up</Text>
    </View>
  );
}

 

그런 다음 React Native에서 TextInput 및 StyleSheet 구성 요소를 가져와야 합니다.
import { View, Text, Button, TextInput, StyleSheet } from 'react-native';

 

각 TextInput의 스타일을 개별적으로 지정할 수 있지만 빠르게 반복됩니다. 대신 파일 하단(구성 요소 외부)에 다음을 추가합니다.

 

const styles = StyleSheet.create({
  outer: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  inner: {
    width: 240,
  },
  header: {
    fontSize: 24,
    fontWeight: 'bold',
    marginBottom: 20,
  },
  input: {
    borderWidth: 1,
    borderColor: '#ccc',
    borderRadius: 4,
    paddingVertical: 8,
    paddingHorizontal: 12,
    marginBottom: 16,
  },
  error: {
    marginBottom: 20,
    color: 'red',
  },
});

스타일 개체를 사용하여 이제 서로 다른 구성 요소 간에 스타일을 공유할 수 있습니다.

이제 가입 양식 구성 요소를 수정하겠습니다. 외부 컨테이너, 양식을 보관할 내부 컨테이너, 사용자 이름 및 암호 필드에 대한 세 개의 TextInput 및 제출을 처리하는 버튼을 추가하겠습니다.

 

function Signup() {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [confirmPassword, setConfirmPassword] = useState('');
  const [error, setError] = useState(null);

  const createAccount = () => {
    // create account
  };

  return (
    <View style={styles.outer}>
      <View style={styles.inner}>
        <Text style={styles.header}>Signup</Text>

        <TextInput
          value={email}
          onChangeText={setEmail}
          keyboardType="email-address"
          placeholder="Enter email address"
          autoCapitalize="none"
          placeholderTextColor="#aaa"
          style={styles.input}
        />
        <TextInput
          value={password}
          onChangeText={setPassword}
          secureTextEntry
          placeholder="Enter password"
          autoCapitalize="none"
          placeholderTextColor="#aaa"
          style={styles.input}
        />
        <TextInput
          value={confirmPassword}
          onChangeText={setConfirmPassword}
          secureTextEntry
          placeholder="Confirm password"
          autoCapitalize="none"
          placeholderTextColor="#aaa"
          style={styles.input}
        />

        <Button
          title="Create Account"
          onPress={createAccount}
          disabled={!email || !password || !confirmPassword}
        />
      </View>
    </View>
  );
}

 

React Native를 처음 사용하는 경우 여기에서 주의해야 할 몇 가지 사항이 있습니다.
이메일 주소 TextInput에 대해 keyboardType 소품을 이메일 주소로 설정합니다. 즉, 이 필드에 입력할 때 이메일 주소를 입력하도록 설계된 올바른 기본 키보드가 장치에 표시됩니다. (그렇지 않으면 사용자가 @ 기호를 찾기 위해 다른 키보드를 수동으로 탐색해야 하는데 이는 성가신 일입니다).
 

암호 필드의 경우 텍스트가 일반 텍스트로 표시되지 않고 입력될 때 별표 표시되도록 하는 secureTextEntry 속성을 추가합니다.

 

 
마지막으로 제출 버튼의 경우 세 필드 중 하나라도 채워지지 않았는지 확인하여 비활성화된 prop 을 설정합니다. 이 확인 결과가 참이면 버튼이 비활성화됩니다. 세 가지 모두 값이 있고 확인 결과 false가 반환되면 disabled가 false로 설정되고 버튼을 클릭할 수 있게 됩니다.

 

이제 createAccount 함수를 연결하여 실제로 Firebase를 만들고 계정을 만들 수 있습니다. createUserWithEmailAndPassword 메소드를 사용하겠습니다.

 

import { onAuthStateChanged, signOut, createUserWithEmailAndPassword } from 'firebase/auth';

 

createAccount 함수에서 메서드를 추가하고 인증 인스턴스와 이메일 및 비밀번호를 전달합니다. 그러면 제공된 자격 증명으로 계정을 생성하기 위해 Firebase에 요청을 보냅니다.

계정이 성공적으로 생성되면 App 구성 요소에서 onAuthStateChanged 메서드가 실행되고 사용자에게 로그인 페이지가 표시됩니다. 실패하면 비동기 함수의 catch 부분이 실행되고 오류가 오류 상태에 기록되고 사용자에게 표시됩니다.
 
const createAccount = async () => {
  try {
    await createUserWithEmailAndPassword(auth, email, password);
  } catch (e) {
    setError('There was a problem creating your account');
  }
};

 

한 가지 더 - 두 비밀번호 필드가 일치하는지 확인하는 검사를 추가해 보겠습니다. try catch 블록에서 암호를 확인하고 ConfirmPassword 상태 값이 일치하는지 확인하는 조건을 추가합니다. 일치하지 않으면 사용자에게 일치하지 않음을 알리는 오류 메시지를 설정합니다.
const createAccount = async () => {
  try {
    if (password === confirmPassword) {
      await createUserWithEmailAndPassword(auth, email, password);
    } else {
      setError("Passwords don't match");
    }
  } catch (e) {
    setError('There was a problem creating your account');
  }
};
 
이전에 StyleSheet 개체의 일부로 추가한 오류 스타일을 사용하여 제목 아래에 오류 메시지를 추가해 보겠습니다.
{
  error && <Text style={styles.error}>{error}</Text>;
}

 

전체 가입 구성 요소는 다음과 같습니다. 구성 단계를 올바르게 수행했다고 가정하면 이제 양식을 작성하고 계정 세부정보가 Firebase 콘솔에 표시되는 것을 볼 수 있습니다!

 

function Signup() {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [confirmPassword, setConfirmPassword] = useState('');
  const [error, setError] = useState(null);

  const createAccount = async () => {
    try {
      if (password === confirmPassword) {
        await createUserWithEmailAndPassword(auth, email, password);
      } else {
        setError("Passwords don't match");
      }
    } catch (e) {
      setError('There was a problem creating your account');
    }
  };

  return (
    <View style={styles.outer}>
      <View style={styles.inner}>
        <Text style={styles.header}>Signup</Text>

        {error && <Text style={styles.error}>{error}</Text>}

        <TextInput
          value={email}
          onChangeText={setEmail}
          keyboardType="email-address"
          placeholder="Enter email address"
          autoCapitalize="none"
          placeholderTextColor="#aaa"
          style={styles.input}
        />
        <TextInput
          value={password}
          onChangeText={setPassword}
          secureTextEntry
          placeholder="Enter password"
          autoCapitalize="none"
          placeholderTextColor="#aaa"
          style={styles.input}
        />
        <TextInput
          value={confirmPassword}
          onChangeText={setConfirmPassword}
          secureTextEntry
          placeholder="Confirm password"
          autoCapitalize="none"
          placeholderTextColor="#aaa"
          style={styles.input}
        />

        <Button
          title="Create Account"
          onPress={createAccount}
          disabled={!email || !password || !confirmPassword}
        />
      </View>
    </View>
  );
}

 

 

로그인 양식 작성
 
이제 기존 계정을 실제로 사용할 수 있도록 로그인 양식을 작성할 수 있습니다. Login이라는 새 구성 요소를 만들고 몇 가지 자리 표시자 콘텐츠를 추가합니다.
function Login() {
  return (
    <View style={styles.outer}>
      <View style={styles.inner}>
        <Text style={styles.header}>Login</Text>
      </View>
    </View>
  );
}
 
이제 몇 가지 화면이 있으므로 기본 라우팅을 추가해야 합니다. 사용자가 기존 계정에 로그인하거나 새 계정을 만드는 것 중에서 선택할 수 있기를 바랍니다. 앱 구성 요소에서 현재 화면을 유지할 상태 값을 추가할 것입니다.
const [screen, setScreen] = useState(null);
getScreen 메서드에서 logIn이 true인 경우 화면 값에 관계없이 LoggedIn 화면을 반환하도록 설정합니다. 로그인하지 않고 screen이 signup으로 설정되어 있으면 signup 구성 요소를 반환하고 screen이 null이거나 다른 것으로 설정되어 있으면 로그인 구성 요소를 반환합니다.
const getScreen = () => {
  if (loggedIn) return <LoggedIn />;
  if (screen === 'signup') return <Signup />;
  return <Login />;
};

 

로그아웃했는지 확인하고 앱을 열 때 로그인 화면이 표시되어야 합니다.

 

이제 로그인 화면과 가입 화면 사이를 전환하는 방법이 필요합니다. App 구성 요소에서 setScreen 메서드를 다음과 같이 Login 구성 요소와 Signup 구성 요소 모두에 prop으로 전달합니다.
const getScreen = () => {
  if (loggedIn) return <LoggedIn />;
  if (screen === 'signup') return <Signup setScreen={setScreen} />;
  return <Login setScreen={setScreen} />;
};
 
이제 로그인 화면에서 화면 값을 "가입"으로 설정하는 링크를 추가해 보겠습니다. 먼저 React Native에서 TouchableOpacity 구성 요소를 가져와야 합니다.
import { View, Text, Button, TextInput, StyleSheet, TouchableOpacity } from 'react-native';

 

스타일 개체에서 링크 스타일을 추가합니다.
const styles = StyleSheet.create({
  // ...
  link: {
    color: 'blue',
    marginBottom: 20,
  },
});

 

그런 다음 가입할 화면 값을 설정하는 로그인 화면에 대한 링크를 추가할 수 있습니다.

function Login({ setScreen }) {
  return (
    <View style={styles.outer}>
      <View style={styles.inner}>
        <Text style={styles.header}>Login</Text>
        <TouchableOpacity onPress={() => setScreen('signup')}>
          <Text style={styles.link}>Create an account</Text>
        </TouchableOpacity>
      </View>
    </View>
  );
}
 
이제 Signup 구성 요소에서 동일한 작업을 수행하여 둘 사이를 전환할 수 있습니다.
 
function Signup({ setScreen }) {
  // ..

  return (
    <View style={styles.outer}>
      <View style={styles.inner}>
        // ...
        <TouchableOpacity onPress={() => setScreen('login')}>
          <Text style={styles.link}>Login to existing account</Text>
        </TouchableOpacity>
        // ...
      </View>
    </View>
  );
}
 
앱을 다시 로드하면 이제 서로 다른 두 화면 사이를 전환할 수 있습니다.

 
이것은 이 튜토리얼의 목적을 위한 매우 기본적인 라우팅 구현입니다. 프로덕션 앱을 빌드하는 경우 React Navigation과 같은 적절한 라우팅 솔루션을 사용하는 것이 좋습니다.
로그인 화면을 구축하는 것은 등록 화면에서 많은 로직과 레이아웃의 용도를 변경할 수 있으므로 매우 간단합니다. 이메일, 비밀번호, Firebase에서 반환한 오류 및 관련 구성 요소에 대한 상태 값을 추가하는 것으로 시작하겠습니다.
 
function Login({ setScreen }) {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [error, setError] = useState(null);

  const loginUser = () => {
    //
  };

  return (
    <View style={styles.outer}>
      <View style={styles.inner}>
        <Text style={styles.header}>Login</Text>

        {error && <Text style={styles.error}>{error}</Text>}

        <TouchableOpacity onPress={() => setScreen('signup')}>
          <Text style={styles.link}>Create an account</Text>
        </TouchableOpacity>

        <TextInput
          value={email}
          onChangeText={setEmail}
          keyboardType="email-address"
          placeholder="Enter email address"
          autoCapitalize="none"
          placeholderTextColor="#aaa"
          style={styles.input}
        />
        <TextInput
          value={password}
          onChangeText={setPassword}
          secureTextEntry
          placeholder="Enter password"
          autoCapitalize="none"
          placeholderTextColor="#aaa"
          style={styles.input}
        />
        <Button title="Login" onPress={loginUser} disabled={!email || !password} />
      </View>
    </View>
  );
}

 

보시다시피 loginUser 함수는 현재 실제로 아무 작업도 수행하지 않습니다. 작동하려면 Firebase에서 signInWithEmailAndPassword 메서드를 가져와야 합니다.
import {
  onAuthStateChanged,
  signOut,
  createUserWithEmailAndPassword,
  signInWithEmailAndPassword,
} from 'firebase/auth';

 

그런 다음 인증 인스턴스와 이메일 및 암호 값을 전달하여 loginUser 함수에서 이 메서드를 사용할 수 있습니다.
const loginUser = async () => {
  try {
    await signInWithEmailAndPassword(auth, email, password);
  } catch (error) {
    //
  }
};

 

이제 사용자에게 발생할 수 있는 모든 오류를 처리해야 합니다. 사용자가 잘못된 자격 증명을 입력하거나 이메일이 이미 사용 중인 경우 명시적으로 처리합니다. 그렇지 않으면 일반적인 오류를 반환합니다.
 
const loginUser = async () => {
  try {
    await signInWithEmailAndPassword(auth, email, password);
  } catch (error) {
    if (error.code === 'auth/invalid-email' || error.code === 'auth/wrong-password') {
      setError('Your email or password was incorrect');
    } else if (error.code === 'auth/email-already-in-use') {
      setError('An account with this email already exists');
    } else {
      setError('There was a problem with your request');
    }
  }
};

 

이제 가입 과정에서 생성한 자격 증명으로 로그인할 수 있습니다.
 
한 가지 더 처리해야 할 사항이 있습니다. 비밀번호 재설정 양식을 추가해야 합니다.

 

비밀번호 재설정 양식 추가

 

암호 재설정 양식을 포함할 새 구성 요소를 추가해 보겠습니다.
function ResetPassword() {
  return (
    <View style={styles.outer}>
      <View style={styles.inner}>
        <Text style={styles.header}>Reset Password</Text>
      </View>
    </View>
  );
}
 
로그인 양식에 화면을 "비밀번호 재설정"으로 설정하는 링크를 추가합니다.
<TouchableOpacity onPress={() => setScreen('reset-password')}>
  <Text style={[styles.link, { color: '#333' }]}>I've forgotten my password</Text>
</TouchableOpacity>

 

기본 앱 구성 요소의 getScreen 함수 내에서 screen 값이 "reset-password"로 설정된 경우 ResetPassword 구성 요소를 렌더링하는 줄을 추가합니다.
const getScreen = () => {
  if (loggedIn) return <LoggedIn />;
  if (screen === 'signup') return <Signup setScreen={setScreen} />;
  if (screen === 'reset-password') return <ResetPassword setScreen={setScreen} />;
  return <Login setScreen={setScreen} />;
};
 
ResetPassword 기능에서 로그인 화면으로 돌아가는 링크를 추가합니다.
function ResetPassword({ setScreen }) {
  return (
    <View style={styles.outer}>
      <View style={styles.inner}>
        <Text style={styles.header}>Reset Password</Text>

        <TouchableOpacity onPress={() => setScreen('login')}>
          <Text style={styles.link}>Back to login</Text>
        </TouchableOpacity>
      </View>
    </View>
  );
}

 

이제 로그인 화면과 암호 재설정 화면 사이를 전환할 수 있습니다.

이제 로그인 양식에서 이메일 입력을 복사하고 사용자 이메일에 대한 상태 값과 제출 버튼을 추가할 수 있습니다. 다른 화면과 마찬가지로 오류 처리도 추가합니다. 한 가지 더 - 이 작업의 결과를 처리하기 위해 이 인스턴스에서 onAuthStateChanged 메서드를 사용하지 않을 것이므로 사용자에게 요청이 처리되었음을 알리고 이메일을 확인하도록 수동으로 트리거해야 합니다. 이를 위해 나중에 사용할 submit이라는 또 다른 상태를 추가합니다.

 

function ResetPassword({ setScreen }) {
  const [email, setEmail] = useState('');
  const [error, setError] = useState(null);
  const [submitted, setSubmitted] = useState(false);

  const resetUserPassword = () => {
    //
  };

  return (
    <View style={styles.outer}>
      <View style={styles.inner}>
        <Text style={styles.header}>Reset Password</Text>

        {error && <Text style={styles.error}>{error}</Text>}

        <TouchableOpacity onPress={() => setScreen('login')}>
          <Text style={styles.link}>Back to login</Text>
        </TouchableOpacity>

        <TextInput
          value={email}
          onChangeText={setEmail}
          keyboardType="email-address"
          placeholder="Enter email address"
          autoCapitalize="none"
          placeholderTextColor="#aaa"
          style={styles.input}
        />

        <Button title="Reset Password" onPress={resetUserPassword} disabled={!email} />
      </View>
    </View>
  );
}

 

비밀번호 재설정 요청을 처리하려면 Firebase에서 sendPasswordResetEmail 메소드를 가져와야 합니다.
import {
  onAuthStateChanged,
  signOut,
  createUserWithEmailAndPassword,
  signInWithEmailAndPassword,
  sendPasswordResetEmail,
} from 'firebase/auth';

그런 다음 resetUserPassword 함수에서 인증 인스턴스와 사용자가 제공한 이메일 주소를 전달하여 이 메서드를 호출합니다. 요청이 성공하면 submit을 true로 설정하고 실패하면 기본 오류 처리를 제공합니다.

 

const resetUserPassword = async () => {
  try {
    await sendPasswordResetEmail(auth, email);
    setSubmitted(true);
    setError(null);
  } catch (error) {
    if (error.code === 'auth/user-not-found') {
      setError('User not found');
    } else {
      setError('There was a problem with your request');
    }
  }
};
이제 제출된 값을 사용하여 확인 메시지를 추가해 보겠습니다. 제출이 참이면 확인 메시지를 표시하고 거짓이면 이메일 입력 및 제출 버튼을 표시합니다.
function ResetPassword({ setScreen }) {
  const [email, setEmail] = useState('');
  const [error, setError] = useState(null);
  const [submitted, setSubmitted] = useState(false);

  const resetUserPassword = async () => {
    try {
      await sendPasswordResetEmail(auth, email);
      setSubmitted(true);
      setError(null);
    } catch (error) {
      if (error.code === 'auth/user-not-found') {
        setError('User not found');
      } else {
        setError('There was a problem with your request');
      }
    }
  };

  return (
    <View style={styles.outer}>
      <View style={styles.inner}>
        <Text style={styles.header}>Reset Password</Text>

        {error && <Text style={styles.error}>{error}</Text>}

        <TouchableOpacity onPress={() => setScreen('login')}>
          <Text style={styles.link}>Back to login</Text>
        </TouchableOpacity>

        {submitted ? (
          <Text>Please check your email for a reset password link.</Text>
        ) : (
          <>
            <TextInput
              value={email}
              onChangeText={setEmail}
              keyboardType="email-address"
              placeholder="Enter email address"
              autoCapitalize="none"
              placeholderTextColor="#aaa"
              style={styles.input}
            />

            <Button title="Reset Password" onPress={resetUserPassword} disabled={!email} />
          </>
        )}
      </View>
    </View>
  );
}

 

이제 이메일 주소를 입력하고(계정이 해당 이메일에 연결되어 있다고 가정) 비밀번호 재설정 이메일을 받을 수 있습니다.

결론

 

읽어 주셔서 감사합니다. React Native에서 Firebase 인증을 시작하고 실행하는 데 도움이 되었기를 바랍니다. 이 예제의 전체 코드는 아래를 참조하거나 Github 저장소를 확인하세요. Github repo
 

GitHub - atomlabdev/react-native-firebase-auth-example

Contribute to atomlabdev/react-native-firebase-auth-example development by creating an account on GitHub.

github.com

.

 

즉시 Firebase 및 Firebase 인증 설정을 시작하려면 포털 - Portal - my free React Native login template 을 확인하세요.

App.js 전체 소스

 

import React, { useState } from 'react';
import { View, Text, Button, TextInput, StyleSheet, TouchableOpacity } from 'react-native';
import {
  onAuthStateChanged,
  signOut,
  createUserWithEmailAndPassword,
  signInWithEmailAndPassword,
  sendPasswordResetEmail,
} from 'firebase/auth';

import { auth } from './firebase';

function LoggedIn() {
  const logout = async () => {
    try {
      await signOut(auth);
    } catch (e) {
      console.error(e);
    }
  };

  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Text>Logged in</Text>
      <Button title="Log out" onPress={logout} />
    </View>
  );
}

function Signup({ setScreen }) {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [confirmPassword, setConfirmPassword] = useState('');
  const [error, setError] = useState(null);

  const createAccount = async () => {
    try {
      if (password === confirmPassword) {
        await createUserWithEmailAndPassword(auth, email, password);
      } else {
        setError("Passwords don't match");
      }
    } catch (e) {
      setError('There was a problem creating your account');
    }
  };

  return (
    <View style={styles.outer}>
      <View style={styles.inner}>
        <Text style={styles.header}>Signup</Text>

        {error && <Text style={styles.error}>{error}</Text>}

        <TouchableOpacity onPress={() => setScreen('login')}>
          <Text style={styles.link}>Login to existing account</Text>
        </TouchableOpacity>

        <TextInput
          value={email}
          onChangeText={setEmail}
          keyboardType="email-address"
          placeholder="Enter email address"
          autoCapitalize="none"
          placeholderTextColor="#aaa"
          style={styles.input}
        />
        <TextInput
          value={password}
          onChangeText={setPassword}
          secureTextEntry
          placeholder="Enter password"
          autoCapitalize="none"
          placeholderTextColor="#aaa"
          style={styles.input}
        />
        <TextInput
          value={confirmPassword}
          onChangeText={setConfirmPassword}
          secureTextEntry
          placeholder="Confirm password"
          autoCapitalize="none"
          placeholderTextColor="#aaa"
          style={styles.input}
        />

        <Button
          title="Create Account"
          onPress={createAccount}
          disabled={!email || !password || !confirmPassword}
        />
      </View>
    </View>
  );
}

function Login({ setScreen }) {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [error, setError] = useState(null);

  const loginUser = async () => {
    try {
      await signInWithEmailAndPassword(auth, email, password);
    } catch (error) {
      if (error.code === 'auth/invalid-email' || error.code === 'auth/wrong-password') {
        setError('Your email or password was incorrect');
      } else if (error.code === 'auth/email-already-in-use') {
        setError('An account with this email already exists');
      } else {
        setError('There was a problem with your request');
      }
    }
  };

  return (
    <View style={styles.outer}>
      <View style={styles.inner}>
        <Text style={styles.header}>Login</Text>

        {error && <Text style={styles.error}>{error}</Text>}

        <TouchableOpacity onPress={() => setScreen('signup')}>
          <Text style={styles.link}>Create an account</Text>
        </TouchableOpacity>

        <TextInput
          value={email}
          onChangeText={setEmail}
          keyboardType="email-address"
          placeholder="Enter email address"
          autoCapitalize="none"
          placeholderTextColor="#aaa"
          style={styles.input}
        />
        <TextInput
          value={password}
          onChangeText={setPassword}
          secureTextEntry
          placeholder="Enter password"
          autoCapitalize="none"
          placeholderTextColor="#aaa"
          style={styles.input}
        />

        <TouchableOpacity onPress={() => setScreen('reset-password')}>
          <Text style={[styles.link, { color: '#333' }]}>I've forgotten my password</Text>
        </TouchableOpacity>

        <Button title="Login" onPress={loginUser} disabled={!email || !password} />
      </View>
    </View>
  );
}

function ResetPassword({ setScreen }) {
  const [email, setEmail] = useState('');
  const [error, setError] = useState(null);
  const [submitted, setSubmitted] = useState(false);

  const resetUserPassword = async () => {
    try {
      await sendPasswordResetEmail(auth, email);
      setSubmitted(true);
      setError(null);
    } catch (error) {
      if (error.code === 'auth/user-not-found') {
        setError('User not found');
      } else {
        setError('There was a problem with your request');
      }
    }
  };

  return (
    <View style={styles.outer}>
      <View style={styles.inner}>
        <Text style={styles.header}>Reset Password</Text>

        {error && <Text style={styles.error}>{error}</Text>}

        <TouchableOpacity onPress={() => setScreen('login')}>
          <Text style={styles.link}>Back to login</Text>
        </TouchableOpacity>

        {submitted ? (
          <Text>Please check your email for a reset password link.</Text>
        ) : (
          <>
            <TextInput
              value={email}
              onChangeText={setEmail}
              keyboardType="email-address"
              placeholder="Enter email address"
              autoCapitalize="none"
              placeholderTextColor="#aaa"
              style={styles.input}
            />

            <Button title="Reset Password" onPress={resetUserPassword} disabled={!email} />
          </>
        )}
      </View>
    </View>
  );
}

export default function App() {
  const [loggedIn, setLoggedIn] = useState(false);
  const [screen, setScreen] = useState(null);

  onAuthStateChanged(auth, (user) => {
    if (user) {
      setLoggedIn(true);
    } else {
      setLoggedIn(false);
    }
  });

  const getScreen = () => {
    if (loggedIn) return <LoggedIn />;
    if (screen === 'signup') return <Signup setScreen={setScreen} />;
    if (screen === 'reset-password') return <ResetPassword setScreen={setScreen} />;
    return <Login setScreen={setScreen} />;
  };

  return <View style={{ flex: 1 }}>{getScreen()}</View>;
}

const styles = StyleSheet.create({
  outer: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  inner: {
    width: 240,
  },
  header: {
    fontSize: 24,
    fontWeight: 'bold',
    marginBottom: 20,
  },
  input: {
    borderWidth: 1,
    borderColor: '#ccc',
    borderRadius: 4,
    paddingVertical: 8,
    paddingHorizontal: 12,
    marginBottom: 16,
  },
  error: {
    marginBottom: 20,
    color: 'red',
  },
  link: {
    color: 'blue',
    marginBottom: 20,
  },
});

 

 

원본 출처

 

https://www.atomlab.dev/tutorials/email-authentication-react-native-firebase

 

How to setup email authentication with React Native and Firebase

A guide on setting up email authentication with React Native and Firebase - including login, signup and password reset flows

www.atomlab.dev