이것저것 해보기🌼

[React] firebase 회원가입/로그인 구현하기 (이메일, 비밀번호 사용) 본문

프로젝트/참나무농원

[React] firebase 회원가입/로그인 구현하기 (이메일, 비밀번호 사용)

realtree 2024. 6. 23. 20:47

 

 

Firebase 인증 소개

firebase는 인증, 데이터베이스 등 다양한 기능을 제공한다.

그 중에서 인증 기능을 활용해 로그인을 쉽게 구현할 수 있다. 구글, 페이스북 등 소셜 로그인도 가능하다. 

 

가이드 보기 : https://firebase.google.com/docs/auth/web/start?hl=ko

 

웹사이트에서 Firebase 인증 시작하기  |  Firebase Authentication

Google I/O 2023에서 Firebase의 주요 소식을 확인하세요. 자세히 알아보기 의견 보내기 웹사이트에서 Firebase 인증 시작하기 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분

firebase.google.com

 

다양한 소셜 로그인 기능이 있지만, 당장은 이메일/비밀번호 방식만 사용할 예정이다.

 


이메일/비밀번호 방식을 추가한다.

 

 

firebase는 이메일 인증 기능도 제공하는데, 필요하다면 인증을 위한 이메일 내용도 커스터마이징 가능하다. 

 

 

1. 회원가입

가이드에 아래와 같이 createUserWithEmailAndPassword 메소드를 활용한 회원가입 방법이 나와있다.

import { getAuth, createUserWithEmailAndPassword } from "firebase/auth";

const auth = getAuth();
createUserWithEmailAndPassword(auth, email, password)
  .then((userCredential) => {
    // Signed in 
    const user = userCredential.user;
    // ...
  })
  .catch((error) => {
    const errorCode = error.code;
    const errorMessage = error.message;
    // ..
  });

 

 

 

내 코드

위 매뉴얼 코드를 바탕으로 작성한 코드이다. 현재 사용자가 로그인 상태인지 아닌지의 여부를 저장해야하는데 redux 스토어에 담는 방식을 사용했다.

import { useNavigate } from "react-router-dom";
import Form from "../../../components/Form/Form"
import { useState } from "react";
import app from '../../../firebase';
import { createUserWithEmailAndPassword, getAuth } from 'firebase/auth';
import { useDispatch } from "react-redux";
import { setUser } from "../../../store/user/user.slice";

const SignUp = () => { 
	const navigate = useNavigate();
	const [firebaseError, setFirebaseError] = useState("");
	const dispatch = useDispatch();

	const auth = getAuth(app);
	const handleSignupAndLogin = (email, password) => {
		createUserWithEmailAndPassword(auth, email, password)
		.then((userCredential) => {
			// 리덕스 스토어에 담는 로직
			dispatch(setUser({
				email: userCredential.user.email,
				token: userCredential.user.refreshToken,
				id: userCredential.user.uid
			}))
			navigate('/')
		})
		.catch(error => {
			return error && setFirebaseError("이메일 또는 비밀번호가 잘못되었습니다.");
		})
	}
	return (
		<Form 
			title={"가입하기"}
			getDataForm={handleSignupAndLogin}
			firebaseError={firebaseError}
		/>
	)
}

export default SignUp

 

 

2. 로그인

로그인도 간단히 signInWithEmailAndPassword 메소드를 사용하여 구현 가능하다.

import { getAuth, signInWithEmailAndPassword } from "firebase/auth";

const auth = getAuth();
signInWithEmailAndPassword(auth, email, password)
  .then((userCredential) => {
    // Signed in 
    const user = userCredential.user;
    // ...
  })
  .catch((error) => {
    const errorCode = error.code;
    const errorMessage = error.message;
  });

 

 

내 코드

email, token, id 세 가지 정보를 사용해서 User 정보를 저장하도록 했다.

import { useState } from 'react'
import Form from '../../../components/Form/Form'
import { useNavigate } from 'react-router-dom'
import { getAuth, signInWithEmailAndPassword } from 'firebase/auth';
import app from '../../../firebase';
import { useDispatch } from 'react-redux';
import { setUser } from '../../../store/user/user.slice';

const SignIn = () => {
	const navigate = useNavigate();
	const [firebaseError, setFirebaseError] = useState("");
	const dispatch = useDispatch();

	const auth = getAuth(app);
	const handleLogin = (email, password) => {
		signInWithEmailAndPassword(auth, email, password)
		.then(userCredential => {
			dispatch(setUser({
				email: userCredential.user.email,
				token: userCredential.user.refreshToken,
				id: userCredential.user.uid
			}))
			navigate('/')
		})
		.catch(error => {
			return error && setFirebaseError("이메일 또는 비밀번호가 잘못되었습니다.")
		})
	}
	return (
		<Form
			title={"로그인"}
			getDataForm={handleLogin}
			firebaseError={firebaseError}
		/>
	)
}

export default SignIn

 

 

 

3. 화면 UI

react-hook-form

로그인이든 회원가입이든 입력 폼에서는 유효한 입력인지 validation 체크가 필요한데, 이것은 react-hook-form 이라는 라이브러리를 사용했다.

 

최소 글자수, 최대 글자수, 정규표현식으로 이메일 주소에 맞는지 검사 등등을 편하게 가져와서 쓸수 있다.

글자가 입력될때마다 체크할지, 혹은 submit 이벤트가 발생할때 체크할지 등의 세부적인 설정도 가능하다. 

https://www.react-hook-form.com/

 

Home

React hook for form validation without the hassle

www.react-hook-form.com

 

내 코드

그래서 회원가입, 로그인에서 공통적으로 사용한 <Form> 컴포넌트는 아래와 같다.

import styles from './Form.module.scss'
import { useForm } from 'react-hook-form'

const Form = ({ title, getDataForm, firebaseError}) => {

	const { register, handleSubmit, formState: {errors}, reset } = useForm({
		mode: 'onChange'
	}) //onChange | onSubmit | onBlur

	const onSubmit = ({email, password}) => {
		getDataForm(email, password);
		reset();
	}

	const userEmail = {
		required: "필수 입력입니다.",
		pattern: {
			value: /^[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*.[a-zA-Z]{2,3}$/i,
			message: "이메일 형식에 맞지 않습니다.",
		}
	}

	const userPassword = {
		required: "필수 입력입니다.",
		minLength: {
			value: 6,
			message: "최소 6자입니다.",
		},
		maxLength: {
			value: 13,
			message: "최대 13자입니다.",
		}

	}

	return (
		<form onSubmit={handleSubmit(onSubmit)} className={styles.form}>
			<div>
				<input
					type="email"
					placeholder="E-mail"
					{...register("email", userEmail)}
				/>
				{errors?.email &&
					<div>
						<span className={styles.form_error}>
							{errors.email.message}
						</span>
					</div>
				}
			</div>
			<div>
				<input
					type="password"
					placeholder="Password"
					{...register("password", userPassword)}
				/>
				{errors?.password &&
					<div>
						<span className={styles.form_error}>
							{errors.password.message}
						</span>
					</div>
				}
			</div>
			<button type='submit'>{title}</button>
			{firebaseError && 
				<span className={styles.form_error}>{firebaseError}</span>
			}
		</form>
	)
}

export default Form

 

 

Sass

.form {
	display: flex;
	flex-direction: column;
	align-items: center;
	width: 100%;

	div {
			display: flex;
			flex-direction: column;
			align-items: center;
			width: 100%;
			margin-bottom: 10px;
	}

	input {
			width: 80%;
			height: auto;
			padding: 10px 15px;
			color: var(--second-color);
			font-size: 16px;
			border: 1px solid var(--second-color);
			border-radius: 5px;
			outline: none;

			&:focus {
					border: 3px solid var(--second-color);
					border-radius: 5px;
			}
	}

	button {
		width: 87%;
		height: 48px;
		margin: 10px;
		transition: 0.3s all ease;
	}
	
}

.form_error {
	position: relative;
	display: block;
	width: 80%;
	margin-top: 15px;
	padding: 5px;
	font-size: 13px;
	color: white;
	background: #767A89;
	border: 1px solid #767A89;
	border-radius: 5px;
	box-shadow: rgb(0 0 0 / 16%) 0 3px 6px, rgb(0 0 0 / 23%) 0 3px 6px;
}

 

 

테스트

 

먼저 회원가입을 해보고, 내 firebase 콘솔에서 새 사용자가 잘 추가되는지 확인한다.

회원가입이 잘 되었음
로그인도 테스트 완료