Firebase - Project 생성 및 Application 적용, Authentication 회원가입/로그인 (깃허브)
Firebase Project 생성 및 Application 적용부터 Authentication 로그인 과정
Firebase Project 생성 및 Application 적용
NPM을 사용할지 CDN방식을 사용할지 정한다.
필자는 터미널에서 NPM 명령어를 통해 설치했다.
> npm install firebase @10.1.0
2. SDK 모듈 파일 추가
[ firebase.ts ] 혹은 js ()
import { initializeApp } from "firebase/app";
const firebaseConfig = {
apiKey: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
authDomain: "sample-example-aee43.firebaseapp.com",
projectId: "sample-example-aee43",
storageBucket: "sample-example-aee43.appspot.com",
messagingSenderId: "xxxxxxxxxxxx",
appId: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
};
const app = initializeApp(firebaseConfig);
코드 예시이기 때문에 복사해도 실행 안됨. 본인 코드를 사용해야함.
Firebase Authentication 세팅 및 기본 로그인
콘솔화면 중앙의 Authentication 카드상자를 선택한다.
다음 페이지에서 뜨는 시작하기 버튼을 눌러 활성화 한다. (이미지 생략됨)
로그인 방법 탭에서 기본제공업체 - 이메일/비밀번호 방식을 선택한다.
사용설정(Enable) 토글을 On으로 설정후 저장
Application에서 적용한다.
기존 Firebase Configuration을 정의한 모듈 파일에서 설정한다.
import { getAuth } from "firebase/auth"; // 코드 추가!
const auth = getAuth(app); // 코드 추가! firebase/auth를 import해야함
위 코드를 추가한다.
[ firebase.ts ] 혹은 js
import { initializeApp } from "firebase/app";
import { getAuth } from "firebase/auth"; // 코드 추가!
const firebaseConfig = {
/* 생략 */
};
const app = initializeApp(firebaseConfig);
const auth = getAuth(app); // 코드 추가! firebase/auth를 import해야함
어플리케이션 전역에 인증객체를 공급한다.
[ App.tsx ] 혹은 js
export default function App() {
/**
* auth - 인증객체
* currentUser, signOut, updateCurrentUser 등
* 로그인한 사용자, 로그아웃, 사용자정보수정 등 인증관련 정보,기능 제공
* authStateReady() - 인증 상태 준비여부 대기
* Firebase가 쿠키와 토큰을 읽고 백엔드와 통신하여 로그인여부를 확인하는동안 기다린다.
* Promise<void> 객체를 반환한다.
*/
await auth.authStateReady() //인증상태 준비여부 대기
}
일반 회원가입
[ 계정 생성 및 닉네임 설정 ]
import { createUserWithEmailAndPassword, updateProfile } from "firebase/auth"
import { auth } from "./firebase"
/**
* [ 계정 생성 ]
* createUserWithEmailAndPassword(arg1, arg2, arg3)
* 전달받은 받은 인증객체, 이메일, 패스워드를 통해 FireBase에서 인증처리
* 인증성공시 자격증명을 반환한다.
*/
const credentials = await createUserWithEmailAndPassword(auth, /*이메일*/, /*패스워드*/)
*
/**
* [ 닉네임 설정 ]
* updateProfile(arg1, arg2)
* 사용자 정보, 닉네임 객체 를 매개변수로 전달한다.
* 계정 생성 후 반환받은 자격증명 객체로부터 사용자 정보를 가져올 수 있다.
* 닉네임 객체 형태 : {displayName: /* 설정할 닉네임 */}
*/
await updateProfile(credentials.user, {displayName: userInfo.name,})
console.log(credentials.user) //가입 된 사용자 정보 조회
로그인에 성공한 사용자 정보는 auth객체의 currentUser 속성을 통해 조회가 가능하다.
[ CreateAccount.tsx ] 회원가입 폼 샘플
import { createUserWithEmailAndPassword, updateProfile } from "firebase/auth"
import { useState } from "react"
import { auth } from "./firebase"
import { Link, useNavigate } from "react-router-dom"
import { FirebaseError } from "firebase/app"
import GithubButton from "../components/github-btn"
export default function CreateAccount() {
const navigate = useNavigate();
const [isLoading, setLoading] = useState(false);
const [error, setError] = useState("")
const [userInfo, setUserInfo] = useState({name: '', email: '', password: ''})
const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const {target: {name, value}} = e;
// setUserInfo({...userInfo, [name]: value})
setUserInfo(currentUserInfo => ({...currentUserInfo, [name]: value})) // 콜백 상태업데이트
}
const onSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
setError("")
if(isLoading || userInfo.name === "" || userInfo.email === "" || userInfo.password === "") return;
console.log(userInfo.name, userInfo.email, userInfo.password)
try {
setLoading(true)
// 계정 생성
const credentials = await createUserWithEmailAndPassword(auth, userInfo.email, userInfo.password) //인증객체, 이메일, 패스워드 FireBase에 전달 -> 인증성공시 자격증명 반환
// 사용자 프로필이름 지정
await updateProfile(credentials.user, {displayName: userInfo.name,})
// 회원가입 성공시 홈페이지 리다이렉트
navigate("/")
} catch (e) {
// setError
if(e instanceof FirebaseError) { // 회원가입 실패시
setError(e.message)
}
} finally { // navigate에 의해 리다이렉트 되었더라도 무조건 실행된다.
setLoading(false)
}
}
return (
<>
<form onSubmit={onSubmit}>
<input onChange={onChange} name="name" value={name} placeholder="Name" type="text" required/>
<input onChange={onChange} name="email" value={email} placeholder="Email" type="email" required/>
<input onChange={onChange} name="password" value={password} placeholder="Password" type="password" required/>
<input type="submit" value={isLoading ? "Loading...." : "Create Account"}/>
</form>
{error !== "" ? <Error>{error}</Error>: null}
</>
)
}
일반 로그인
import { signInWithEmailAndPassword } from "firebase/auth"
import { auth } from "./firebase"
/**
* [ 로그인 ]
* signInWithEmailAndPassword(arg1, arg2, arg3)
* 전달받은 받은 인증객체, 이메일, 패스워드를 통해 FireBase에서 로그인 인증처리
* 로그인 인증 성공시 자격증명을 반환한다.
* 회원가입이 아닌 로그인 이므로
* 자격증명이 아닌 어플리케이션 전역에 ReadyState 했던 authentication객체로부터
* 로그인이 된 사용자 정보를 조회한다.
*/
const credential = await signInWithEmailAndPassword(auth, /*이메일*/, /*패스워드*/)
console.log(auth.currentUser) // 로그인 된 사용자 정보 조회
[ Login.tsx ] 로그인 폼 샘플
import { signInWithEmailAndPassword } from "firebase/auth"
import { useState } from "react"
import { auth } from "./firebase"
import { Link, useNavigate } from "react-router-dom"
import { FirebaseError } from "firebase/app"
export default function Login() {
const navigate = useNavigate();
const [isLoading, setLoading] = useState(false);
const [userInfo, setUserInfo] = useState({email: '', password: ''})
const [error, setError] = useState("")
const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const {target: {name, value}} = e;
setUserInfo(currentUserInfo => ({...currentUserInfo, [name]: value})) // 콜백 상태업데이트
}
const onSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
setError("")
if(isLoading || userInfo.email === "" || userInfo.password === "") return;
try {
setLoading(true)
// 로그인
await signInWithEmailAndPassword(auth, userInfo.email, userInfo.password)
console.log(auth.currentUser) // 로그인 된 사용자 정보 조회
// 로그인 성공시 홈페이지 리다이렉트
navigate("/")
} catch (e) {
if(e instanceof FirebaseError) { // 로그인 실패시
console.log(e.code, e.message)
setError(e.message)
}
} finally { // navigate에 의해 리다이렉트 되었더라도 무조건 실행된다.
setLoading(false)
}
}
return (
<>
<form onSubmit={onSubmit}>
<input onChange={onChange} name="email" value={email} placeholder="Email" type="email" required/>
<input onChange={onChange} name="password" value={password} placeholder="Password" type="password" required/>
<input onChange={onChange} type="submit" value={isLoading ? "Loading...." : "Log in"}/>
</form>
{error !== "" ? {error}: null}
</>
)
}
갓허브 Auth Social 로그인
Firebase 콘솔의 Authentication에서 새 제공업체 추가를 선택한다.
깃 으로부터 인증키를 받아 저장해야한다.
깃허브 로그인 후 Profile사진을 누르면 열리는 우측 네비게이션에서 Settings선택.
좌측 네비게이션 최 하단의 Developer settings 선택.
좌측 네비게이션 중간 OAuth Apps선택.
[New OAuth App] 버튼 클릭
Application name, Homepage URL, Authentication callback URL 을 입력한다.
Homepage URL을 따로 검사하지는 않으므로 아직 웹사이트가 없으면 Firebase의 로그인 제공업체 단계에서 제공하는 최 하단의 승인 콜백 URL 링크를 넣어준다. (도메인 까지만 넣자!)
Authentication callback URL에는 풀 Link를 모두 입력해줘야한다.
Client ID와 Client secrets 키를 각각 제공받는다.
이때, 한번 제공받은 Client secrets는 다시 제공받을 수 없다.
(타인에게 노출되면 절대 안됨.)
모자이크 된 부분을 각각 Firebase 제공업체 구성 2/2단계에 입력 후 저장한다.
정상적으로 새로운 제공업체가 추가되었다.
import { GithubAuthProvider, signInWithPopup, signInWithRedirect } from "firebase/auth"
import { auth } from "../routes/firebase"
/**
* firebase 인증객체와, 깃허브 인증 제공객체를 함께 전달해야한다.
*/
const provider = new GithubAuthProvider()
const gitPopCredential = await signInWithPopup(auth, provider); // 팝업
const gitRedCredential = await signInWithRedirect(auth, provider); // 페이지로이동
console.log(auth.currentUser)
이때, firebase/auth/cordova가 아닌 firebase/auth경로로 import해야한다.
두가지 방식중 하나를 선택하면 된다. (팝업으로 할지, 페이지를 이동할지)
import { GithubAuthProvider, signInWithPopup } from "firebase/auth"
import { auth } from "../routes/firebase"
import { useState } from "react"
import { useNavigate } from "react-router-dom"
import { FirebaseError } from "firebase/app"
export default function GithubButton() {
const navigate = useNavigate();
const [error, setError] = useState("")
const onClick = async(e: React.React.ReactHTMLElement<HTMLButtonElement>) => {
e.preventDefault();
try {
setError("")
const provider = new GithubAuthProvider()
await signInWithPopup(auth, provider); // 팝업
// await signInWithRedirect(auth, provider); // 페이지로이동
navigate("/")
} catch (e) {
if(e instanceof FirebaseError) { // 로그인 실패시
console.log(e.code, e.message)
setError(e.message)
}
}
}
return (
<>
<button onClick={onClick}>
Contiune with Github
</button>
{error !== "" ? error: null}
</>
)
}