Firebase - jh0152park/Wiki-Notepad GitHub Wiki
JavaScript ํ๋ก์ ํธ์ Firebase ์ถ๊ฐ
Firebase ํ๋ก์ ํธ ๋ง๋ค๊ธฐ
ํ๋ก์ ํธ์ ์ฑ ์ถ๊ฐํ๊ธฐ
iOS / Android / Web ์ ํํ๊ธฐ
npm install firebase
-
firebaseConfig
key ๋ณต์ฌํด๋๊ธฐ -
src
ํด๋๊ฐ ์๋ ์ต์์ ํด๋์.env
ํ์ผ ์์ฑํ๊ธฐ - ๋ณต์ฌํด๋
firebaseConfig
ํค๊ฐ์.env
ํ์ผ์ ๋ณต์ฌํ๊ธฐ -
.gitignore
์.env
๊ฐ ํฌํจ ๋์ด์๋์ง ํ์ธํ๊ธฐ
.env
ํ์ผ์ ๋ง๋ค๋ KEY๊ฐ ์ด๋ฆ ์์ REACT_APP_
์ ๊ผญ ๋ถ์ฌ์ผ ํ๋ค
REACT_APP_API_KEY="my api key"
REACT_APP_AUTH_DOMAIN="my auth domail"
REACT_APP_PROJECT_ID="my project id"
REACT_APP_STORAGE_BUCKET="my sotrage bucket"
REACT_APP_MESSAGING_SENDER_ID="my messaging sender id"
REACT_APP_APP_ID="my app id"
.env ํ์ผ์ key๊ฐ์ ์๋์ฒ๋ผ ์ฌ์ฉํ๋ค
const API_KEY = process.env.REACT_APP_API_KEY;
const AUTH_DOMAIN = process.env.REACT_APP_AUTH_DOMAIN;
...
...
firebase config ์ ์ธํ๊ธฐ
import { initializeApp } from "firebase/app";
const firebaseConfig = {
apiKey: process.env.REACT_APP_API_KEY,
authDomain: process.env.REACT_APP_AUTH_DOMAIN,
projectId: process.env.REACT_APP_PROJECT_ID,
storageBucket: process.env.REACT_APP_STORAGE_BUCKET,
messagingSenderId: process.env.REACT_APP_MESSAGING_SENDER_ID,
appId: process.env.REACT_APP_APP_ID,
};
const app = initializeApp(firebaseConfig);
Doc: https://firebase.google.com/docs/auth/web/password-auth?hl=ko
ํด๋น ์์์ ๊ฒฝ์ฐ Email ์ฃผ์์ ๊ธฐ๋ณธ์ ์ธ Password๋ก ๊ณ์ ์ ๋ง๋ค๊ฒ ๋๋๋ฐ,
๋ฌธ์ ๋ ์ ํจํ์ง ์์ Email ์ฃผ์๋ฅผ ์ฌ์ฉํด๋ ๋ฌธ์ ๊ฐ ์๊ธฐ ๋๋ฌธ์ ์๊ตฌ์ฌํญ์ ์ ํ์ธํด์ผ ํ๋ค.
Firebase ํ๋ก์ ํธ ์ฝ์์์ ์ธ์ฆ -> ๋ก๊ทธ์ธ๋ฐฉ๋ฒ -> ์ด๋ฉ์ผ/๋น๋ฐ๋ฒํธ ์ฌ์ฉ ์ค์ ์ ๋จผ์ ํด์ผํ๋ค.
Create a new account code
async function onSubmit(data: any) {
try {
setCreate(true);
const credentials = await createUserWithEmailAndPassword(
auth,
data.email,
data.password
);
// await updateProfile(credentials.user, {
// displayName: data.name
// })
//
alert("Create Account Done");
} catch (e) {
if (e instanceof FirebaseError) {
const errorCode = e.code;
const errorMessage = e.message;
console.log(`code: ${errorCode}, message: ${errorMessage}`);
}
} finally {
reset();
setCreate(false);
}
}
Email + Password๋ก Email์ธ์ฆ์ ๊ฑฐ์ณ ๊ณ์ ๋ง๋ค๊ธฐ(CreateWithEmailAndPassword + Email Verification)
ํน์ ๋ชจ๋ฅด๋ Firebase console์์ ๋น๋ฐ๋ฒํธ๊ฐ ์๋ email login ํ์ฉํด์ค๋ค.
์ง๊ธ ์์ ์๊ฐํด๋ณด๋, ๊ตณ์ด ์ํด์ค๋ ๋๋ ๋ถ๋ถ์ธ๊ฑฐ ๊ฐ์, ์ด์ฐจํผ createEmailWithPassword๋ฅผ ์ฌ์ฉํ๋๋ฐ ๋ฌธ์ ๊ฐ ์์๊ฑฐ๊ฐ๊ธฐ ๋๋ฌธ์
Workflow
์ด๋ฉ์ผ ๊ณ์ ์ธ์ฆ์ ์ด๋ฉ์ผ + ๋น๋ฐ๋ฒํธ๋ก ๊ณ์ ์ ๋ง๋๋ ๋จ๊ณ
์์ ์ถ๊ฐ์ ์ผ๋ก ์ด๋ฃจ์ด์ง๋ ๊ณผ์ ์ด๋ค.
๋ฐ๋ผ์ ๊ณ์ ์ ์์ฑ๋ง ํ ๋ฟ ์๋์ผ๋ก ๋ก๊ทธ์ธ์ด ๋๋๋ก ํด์๋ ์๋๋ค. (์ด๋ฉ์ผ ์ธ์ฆ์ด ์์ง ์ด๋ฃจ์ด ์ง์ง ์์๊ธฐ ๋๋ฌธ์ด๋ค.)
์ด๋ฉ์ผ๊ณผ ๋น๋ฐ๋ฒํธ๋ก ๊ณ์ ์ ๋ง๋ค์์ผ๋ฉด, ํด๋น ์ด๋ฉ์ผ๋ก Verification link๋ฅผ ์ ์กํ๊ณ , ์ ์ ๊ฐ ์ ๋ ฅํ Email์ด Validํ Email์ด๋ผ๋ฉด ํด๋น link๋ฅผ ํตํด ์ด๋ฉ์ผ ์ธ์ฆ์ ์งํํ๋ค.
๊ทธ ์ดํ Sign in with email์ ํ๋ ๊ณผ์ ์์ user.emailVerfied
๊ฐ True
์ผ ๊ฒฝ์ฐ ์ ์์ ์ผ๋ก ๋ก๊ทธ์ธ์ ์งํํ๊ฒ ๋๊ณ ,
์ธ์ฆ์ด ๋์ง ์์์ ๊ฒฝ์ฐ ๋ก๊ทธ์ธ์ ์ ํํ ์ ์๋ค.
Verification link at email
user.emailVerified ๊ฐ
Send email code
function onSubmit(data: any) {
setCreate(true);
createUserWithEmailAndPassword(auth, data.email, data.password)
.then((userCredential) => {
sendEmailVerification(userCredential.user).then(() => {
alert("send verification email");
console.log(userCredential.user.email);
console.log(userCredential.user.emailVerified);
});
})
.catch((error) => {
const errorCode = error.code;
const errorMessage = error.message;
console.log(`code: ${errorCode}, message: ${errorMessage}`);
})
.finally(() => {
reset();
setCreate(false);
});
}
์๊ฐ๋ณด๋ค ์์ด ๋ง์ด ๊ฐ๋ ๋ถ๋ถ์ด๋ผ, Firebaes๋ฅผ ์ฌ์ฉํ ๋๋ ๊ทธ๋ฅ ๊ตฌ๊ธ์์ ์ง์ํด์ฃผ๋ Auth๋ง ์ฌ์ฉํ๋๊ฒ ํธํ ๊ฑฐ๊ฐ๋ค...
์ฐธ๊ณ : https://velog.io/@hadam/integrate-kakao-login-with-firebase-using-react-and-functions-2
1.์นด์นด์ค ๊ฐ๋ฐ์ ์ฌ์ดํธ ์ด๋
-
๋ด ์ ํ๋ฆฌ์ผ์ด์
์ถ๊ฐ
- ์ฑ ํค ๊ธฐ์ตํ๊ธฐ
- ํ๋ซํผ ์ค์ ํ๊ธฐ => Web ํ๋ซํผ ๋ฑ๋ก
-
์ฌ์ดํธ ๋๋ฉ์ธ ๋ฑ๋กํ๊ธฐ ex)localhost:3000
-
์นด์นด์ค ๋ก๊ทธ์ธ์ด ๋ Redirect URI ๋ฑ๋ก
6-1. ์ํ ํ์ฑํ On
6-2. Redirect URI ๋ฑ๋ก
- ๋์ํญ๋ชฉ => ํ์ํ ๋ฐ์ดํฐ ์ค์ ex)ํ๋กํ ์ ๋ณด, ์ด๋ฉ์ผ, ์ฑ๋ณ, etc...
-
JavaScript Download ์์ Full SDK ๋ณต์ฌ ํ
public/index.html
์ head ๋ถ๋ถ์ ๋ณต์ฌ -
์ฝ๋์์ ๋ณต์ฌํด๋ KEY๊ฐ์ผ๋ก ์ด๊ธฐํ
if (!window.Kakao.isInitialized()) {
window.Kakao.init(process.env.REACT_APP_KAKAO_JAVASCRIPT_KEY);
}
- Kakao ๋ก๊ทธ์ธ ์คํ
function onLoginWithKakao() {
const redirectUri = `${window.location.origin}/login/kakao`;
const scope = [KAKAO_SCOPE_NICKNAME, KAKAO_SCOPE_PROFILE_IMAGE].join(
","
);
window.Kakao.Auth.authorize({
redirectUri,
scope,
});
}
- ๋ก๊ทธ์ธ์ด ์ ์์ ์ผ๋ก ์ด๋ฃจ์ด์ก๋ค๋ฉด, ๋ฏธ๋ฆฌ ์ ์ํด๋ Redirect URL๋ก ์ด๋ํ๊ฒ๋๊ณ Token์ด ํจ๊ป ๋์ด์ด
-
URLSearchParams
๋ฅผ ์ด์ฉํด code(token)๊ฐ์ ๊ฐ๊ณ ์ค๊ณ , ๋ง์ฝ ์๋ค๋ฉด ๋ก๊ทธ์ธ์ ๋ค์ํ๋๋ก ๊ตฌ์ฑ
const navigate = useNavigate();
const searchParams = new URLSearchParams(window.location.search);
const code = searchParams.get("code");
console.log(code);
if (!code) {
navigate("/login");
}
- firebase function์ ์ฌ์ฉํ๊ธฐ ์ํด
npm install firebase-tools
๋ช ๋ น์ด๋ก ์ค์น ์งํ
13-1. ํฐ๋ฏธ๋์ firebase login
์
๋ ฅ ํ ๋ก๊ทธ์ธ (๋ก๊ทธ์ธ์ด ๋์ด ์๋ค๋ฉด, Already logged in as my account
๊ฐ ์ถ๋ ฅ)
13-2. ํฐ๋ฏธ๋์ firebase init functions
์
๋ ฅ
13-3. Use an existing project
์ ํ ํ ํ์ฌ firebase์์ ์ฌ์ฉ์ค์ธ ํ๋ก์ ํธ ์ ํ
13-4. ์ธ์ด๋ ํ์ ์คํฌ๋ฆฝํธ ์ ํ
13-5. ์ดํ ๋ชจ๋ ์ํฐ
13-6. ์ด์ functions/src/index.ts
์ ์ฝ๋ ์์ฑ์ด ๊ฐ๋ฅ
ํ์ํ API๋ค
-
ํด๋ผ์ด์ธํธ๋ก ๋ถํฐ ์ธ๊ฐ ์ฝ๋๋ฅผ ์ ๋ฌ ๋ฐ๋ ํจ์
-
์ธ๊ฐ ์ฝ๋๋ก ํ ํฐ ๋ฐ๊ธ์ ์์ฒญํ ํจ์
-
์นด์นด์ค ์ ์ ์ ๋ณด๋ฅผ ๊ฐ๊ณ ์ค๋ ํจ์
-
Firebase auth user ์์ฑํ๋ ํจ์
-
์์ฑ๋ user id๋ฅผ ์ด์ฉํด custom token์ ์์ฑํ๋ ํจ์
-
ํด๋ผ์ด์ธํธ๋ก custome token์ ์ ๋ฌํ๋ ํจ์
-
npm install express cors
๋ช ๋ น์ด๋ฅผ ์ด์ฉํด ์ค์น -
functions/src/index.ts
ํ์ผ์ express ์ฑ์ ์์ฑ
import * as functions from "firebase-functions";
import * as express from "express";
import * as cors from "cors";
const app = express();
app.use(cors({ origin: true }));
app.post("/kakao", async (req, res) => {
// TODO: API ๊ตฌํํ๊ธฐ
});
exports.auth = functions.https.onRequest(app);
- ํ ํฐ์ ์์ฒญํ๊ธฐ ์ํด์๋ REST APIํค๊ฐ ํ์์ด๊ณ , ์ด๋ [๋ด ์ ํ๋ฆฌ์ผ์ด์ ] > [์ฑ ํค]์์ ํ์ธ ๊ฐ๋ฅ
-
axios๋ฅผ ์ด์ฉํด HTTP ํต์ ์ ์ฒ๋ฆฌํ๊ณ , dotenv๋ ํจ๊ป ์ค์น
npm install dotenv axios
-
getToken ํจ์ ์์ฑ
async function getToken(code: string): Promise<ITokenResponse> {
const body = {
grant_type: "authorization_code",
client_id: process.env.REACT_APP_KAKAO_REST_API_KEY as "",
redirect_uri: process.env.REACT_APP_KAKAO_REDIRECT_URI as "",
code: code,
};
const res = await axios.post(
"https://kauth.kakao.com/oauth/token",
new URLSearchParams(body)
);
return res.data;
}
- getKakaoUser ํจ์ ์์ฑ
async function getKakaoUser(token: string): Promise<KakaoUser> {
const res = await axios.get("https://kapi.kakao.com/v2/user/me", {
headers: { Authorization: `Bearer ${token}` },
});
return res.data;
}
-
npm install firebase-admin
๋ช ๋ ์ด๋ก ์ค์น
๊ฐ์ ธ์จ ์นด์นด์ค ์ ์ ์ ๋ณด๋ฅผ ๋ฐํ์ผ๋ก Firebae Authentication์ ์ด์ฉํด ์ฌ์ฉ์๋ฅผ ์์ฑํด ์ฃผ์ด์ผ ํ๊ณ ,
์ด๋ ์ฌ์ฉ์์ Custom Token์ ์์ฑํ๊ธฐ ์ํด์ Admin SDK๊ฐ ํ์.
21-1. ์๋น์ค ๊ณ์ ์ ๋น๊ณต๊ฐ ํค ํ์ผ ์์ฑ
a. Firebase Console -> Project ์ค์ -> ์๋น์ค ๊ณ์ -> ์ ๋น๊ณต๊ฐ ํค ์์ฑ
b. ์์ฑ๋ ํค๋ download๋๋๋ฐ ๋ณต๊ตฌ๊ฐ ๋ถ๊ฐ๋ฅํ๋ ์ ๊ฐ์ง
c. Download๋ ํค ํ์ผ์ ์ด์ฉํด Admin App์ ์ด๊ธฐํํ๊ธฐ ์ํด์ Secret Manager๋ฅผ ์ด์ฉํด ํ๊ฒฝ์ ๊ตฌ์ฑํด์ผํจ
d. ๋จผ์ ๊ตฌ๊ธ ์ฝ์๋ก ์ด๋ํด ๋ณด์ ๋น๋ฐ์ ์์ฑ. ๋ฐ๋ก๊ฐ๊ธฐ
- ๊ฒฐ์ ์ ๋ณด๊ฐ ์ฐ๋์ด ๋์ด์ผ ๋ณด์ ๋น๋ฐ ์์ฑ์ด ๊ฐ๋ฅ
e. ์ด๋ฆ, ๋ค์ด๋ก๋ ํ๋ ๋น๊ณต๊ฐํค ์ ๋ก๋
f. functions/src/index.ts
์ exports.auth = ๋ถ๋ถ์ ์์ฑํ ๋ณด์ ๋น๋ฐ์ ์ ๊ทผํ ์ ์๋๋ก runWith์ถ๊ฐ
g. Admin app ์ด๊ธฐํ ์ฝ๋ ์์ฑ
- ์ฌ์ฉ์ ๋ง๋ค๊ธฐ
์์ฑํ app์ ์ด์ฉํด auth service๋ฅผ ๋ถ๋ฌ์ค๊ณ ์ ์ ์
๋ฐ์ดํธ๋ฅผ ์๋ํจ.
๋ง์ฝ ์ ์ ๊ฐ ์๋ค๋ฉด auth/user-not-found
์๋ฌ๊ฐ ๋ฐ์ํ๋ฏ๋ก, try-catch๋ฌธ์ ์ด์ฉํด ์ ์ ์์ฑ ์ฝ๋๋ฅผ ์์ฑํด์ผํจ.
์ถ๊ฐ ์ค๋ฅ ์ฝ๋ ๋ชฉ๋ก
-
- firebase deploy --only functions
๋ฐฐํฌ๊ฐ ์๋ฃ๋๋ฉด Firebase Console -> ๋ชจ๋ ์ ํ -> Functions์์ ํ์ธ ๊ฐ๋ฅ
๋ฐฐํฌ ์๋์ --fix ์๋ฌ๊ฐ ๋ฐ์ํ ๊ฒฝ์ฐ
$ (cd functions && npx eslint . --fix)
# or
$ (cd functions && node_modules/eslint/bin/eslint.js . --fix)
๋ฐฐํฌ ์๋์ Missing JSDoc comment
์๋ฌ๊ฐ ๋ฐ์ํ ๊ฒฝ์ฐ, .eslintrc.js
ํ์ผ์ rules
๋ถ๋ถ์ ์๋์ ๊ฐ์ด ์๋ฌ๊ฐ ๋๋ ํจ์๋ฅผ ์ถ๊ฐ
"require-jsdoc": [
"error",
{
require: {
getToken: false,
getKakaoUser: false,
getAdminApp: false,
updateOrCreateUser: false,
},
},
],
์ ๋ฐฉ๋ฒ์ด ๋์ํ์ง ์๋๋ค๋ฉด, ํจ์๋ค์ function์ด ์๋ arrow function์ผ๋ก ๋ค์ ์์ฑํ๋ค.
์ถ๊ฐ์ ์ผ๋ก react-router ์์ deploy functions ์ค ์๋ฌ๊ฐ ๋ฐ์๋๊ณ ์๋ค.
๋ฒ์ 6๋ถํฐ @types/react-router-dom
์ด ํ์ํ์ง ์์ผ๋ฏ๋ก ์ญ์ ํ๋๋ก ํ๋ค. npm uninstall @types/react-router-dom
์ฐธ๊ณ ๋งํฌ
Error: Your project recap-1daad must be on the Blaze (pay-as-you-go) plan to complete this command. Required API cloudbuild.googleapis.com can't be enabled until the upgrade is complete. To upgrade, visit the following URL:
https://console.firebase.google.com/project/recap-1daad/usage/details
๋ ์์๊ฐ์ ์๋ฌ๊ฐ ๋ฐ์ํ ๊ฒฝ์ฐ, firebase console์์ ์๊ธ์ ๋ฅผ ์์ง ๋ณ๊ฒฝํ์ง ์์์ ๋ฐ์ํ๋ ์๋ฌ์ด๋ค.
์ด๋ฏธ ๊ฒฐ์ ์ ๋ณด๋ ์
๋ ฅํด ๋์์ผ๋ฏ๋ก ์ฝ์์์ ์๊ธ์ ๋ฅผ Spark ์์ Blaze๋ก ๋ณ๊ฒฝํ์.
์ดํ ๋ํ๋ก์ด ์๋์ ๋น๋ฒํ๊ฒ ์๋ฌ๊ฐ ๋ฐ์ํ๋๋ฐ, ์๋ฌ๋ฅผ ์ ์ฒ๋ฆฌํ๊ณ ๋ค์ ํ์ธํด๋ณด์. (dependencies๊ฐ ์ ์ค์น ๋์ด์๋์ง ๋ฑ๋ฑ)
๋์์ functions/src/index.ts
ํ์ผ ์์๋ ์๋์ ๊ฐ์ด ๋ฃ์ด์ค์ผ ํจ
exports.auth = functions
.runWith({
secrets: [
"SERVICE_ACCOUNT_KEY",
"KAKAO_CLIENT_SECRET_KEY",
"REACT_APP_KAKAO_REDIRECT_URI",
"REACT_APP_KAKAO_REST_API_KEY",
],
})
.https.onRequest(app);