일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 네트워크
- node
- webpack
- linux
- 리눅스
- 맥
- MAC
- VirtualBox
- vsCode
- avds
- 개발
- react
- unittest
- 센토스
- Chrome
- TensorFlow
- centos
- IOS
- jest
- build
- xcode
- picker
- ReactNative
- PYTHON
- androidstudio
- MachineLearning
- qunit
- Android
- localserver
- Today
- Total
로메오의 블로그
[Firebase] Authentication 로그인 - Google, Facebook, Email 본문
회원가입을 받기위해서 Firebase > Authentication > 로그인 방법으로 이동합니다.
이메일/비밀번호 수정을 선택합니다.
사용 설정 하고 저장합니다.
Google 도 사용설정 하고 저장합니다.
Facebook 사용설정합니다.
OAuth redirection URI를 복사해 둡니다.
Facebook 개발자 센터
https://developers.facebook.com
Facebook 개발자 센터에서 회원가입 / 로그인 합니다.
앱 만들기를 클릭합니다.
Facebook 로그인 설정을 누릅니다.
좌측에 설정을 누르고 복사해둔 OAuth 리디렉션 URI를 붙여넣기 하고 저장합니다.
설정 > 기본설정에서 앱ID와 앱 시크릿 코드를 복사해서 Firebase에 붙여넣기 합니다.
Facebook은 현재 개발 중 상태이기 때문에 localhost에서만 작동합니다.
최종 완성되면 앱 검수를 받아야 실제 사용가능합니다.
HTML 마크업
bootstrap을 이용해서 마크업을 합니다.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Welcome to Firebase Hosting</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.8/css/all.css">
<style media="screen">
#photoGalleryWrap {
display: none
}
#joinScreen {
display: none
}
</style>
</head>
<body>
<div class="container">
<!-- photoUpload -->
<div id="photoGalleryWrap">
<div class="content-area">
<!-- Standard Form -->
<h4>사진선택</h4>
<form action="" method="post" enctype="multipart/form-data" id="uploadForm">
<div class="form-inline">
<div class="form-group">
<input type="file" name="files[]" id="uploadFiles">
</div>
<button type="submit" class="btn btn-sm btn-primary" id="btnUploadSubmit">Upload files</button>
</div>
</form>
<div class="row text-center text-lg-left" id="gallery">
<div class="col-lg-3 col-md-4 col-6">
<a href="#" class="d-block mb-4 h-100">
<img class="img-fluid img-thumbnail" src="https://source.unsplash.com/pWkk7iiCoDM/400x300"
alt="">
</a>
</div>
<div class="col-lg-3 col-md-4 col-6">
<a href="#" class="d-block mb-4 h-100">
<img class="img-fluid img-thumbnail" src="https://source.unsplash.com/aob0ukAYfuI/400x300"
alt="">
</a>
</div>
<div class="col-lg-3 col-md-4 col-6">
<a href="#" class="d-block mb-4 h-100">
<img class="img-fluid img-thumbnail" src="https://source.unsplash.com/EUfxH-pze7s/400x300"
alt="">
</a>
</div>
<div class="col-lg-3 col-md-4 col-6">
<a href="#" class="d-block mb-4 h-100">
<img class="img-fluid img-thumbnail" src="https://source.unsplash.com/M185_qYH8vg/400x300"
alt="">
</a>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="form-group">
<button type="submit" class="btn btn-primary btn-block" id="btnLogout"> 로그아웃
</button>
</div> <!-- form-group// -->
</div>
</div> <!-- .row// -->
</div>
</div>
<div id="userLoginWrap">
<div class="card">
<article class="card-body" id="loginScreen">
<a href="#" class="float-right btn btn-outline-primary" id="btnToJoin">이메일 회원가입</a>
<h4 class="card-title mb-4 mt-1">로그인</h4>
<p>
<a href="" class="btn btn-block btn-outline-danger" id="btnGoogle">
<i class="fab fa-google"></i> 구글 로그인
</a>
<a href="" class="btn btn-block btn-outline-primary" id="btnFacebook">
<i class="fab fa-facebook-f"></i> 페이스북 로그인
</a>
</p>
<hr>
<form>
<div class="form-group">
<input name="" class="form-control" placeholder="Email" type="email" id="userLoginEmail">
</div> <!-- form-group// -->
<div class="form-group">
<input class="form-control" placeholder="******" type="password" id="userLoginPassword">
</div> <!-- form-group// -->
<div class="row">
<div class="col-md-6">
<div class="form-group">
<button type="submit" class="btn btn-primary btn-block" id="btnLogin"> 로그인
</button>
</div> <!-- form-group// -->
</div>
<div class="col-md-6 text-right">
<a class="small" href="#" id="btnFindPassword">비밀번호 찾기</a>
</div>
</div> <!-- .row// -->
</form>
</article>
<article class="card-body" id="joinScreen">
<a href="#" class="float-right btn btn-outline-primary" id="btnToLogin">로그인</a>
<h4 class="card-title mb-4 mt-1">회원가입</h4>
<hr>
<form>
<div class="form-group">
<input name="" class="form-control" placeholder="이름" type="text" id="userJoinName">
</div> <!-- form-group// -->
<div class="form-group">
<input name="" class="form-control" placeholder="Email" type="email" id="userJoinEmail">
</div> <!-- form-group// -->
<div class="form-group">
<input class="form-control" placeholder="******" type="password" id="userJoinPassword1">
</div> <!-- form-group// -->
<div class="form-group">
<input class="form-control" placeholder="******" type="password" id="userJoinPassword2">
</div> <!-- form-group// -->
<div class="row">
<div class="col-md-6">
<div class="form-group">
<button type="submit" class="btn btn-primary btn-block" id="btnJoin"> 회원가입
</button>
</div> <!-- form-group// -->
</div>
</div> <!-- .row// -->
</form>
</article>
</div>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
<script defer src="/__/firebase/6.6.2/firebase-app.js"></script>
<script defer src="/__/firebase/6.6.2/firebase-auth.js"></script>
<script defer src="/__/firebase/6.6.2/firebase-database.js"></script>
<script defer src="/__/firebase/6.6.2/firebase-messaging.js"></script>
<script defer src="/__/firebase/6.6.2/firebase-storage.js"></script>
<script defer src="/__/firebase/init.js"></script>
<script defer src="index.js"></script>
</body>
</html>
로그인 화면
이메일 회원가입 화면
갤러리 화면
Google 로그인
javascript는 ES6의 Class로 제작되었기 때문에 크롬 등 최신 브라우저에서만 작동합니다.
babel을 사용해서 ES5로 변경하는것은 별도로 다루지 않습니다.
https://romeoh.tistory.com/search/babel
/**
* PhotoApp class
*/
class PhotoApp {
/**
* 생성자
*/
constructor() {
this.init();
this.initEvent();
}
/**
* 변수할당
*/
init() {
// IndexedDB 정보
this.INDEXED_DB_NAME = 'USER'
this.INDEXED_VERSION = 1
this.INDEXED_STORE = 'Users'
this.auth = firebase.auth()
this.$btnGoogle = $('#btnGoogle')
}
/**
* Event Binding
*/
initEvent() {
this.$btnGoogle.on('click', this.onGoogleClick.bind(this))
}
/**
* Google 버튼 눌러서 로그인 / 회원가입
*/
onGoogleClick(e) {
e.preventDefault()
const googleProvider = new firebase.auth.GoogleAuthProvider()
this.auth
.setPersistence(firebase.auth.Auth.Persistence.SESSION)
.then(this.signInWithPopup.bind(this, googleProvider))
.catch(error => console.error('인증상태 설정 중 오류' , error))
}
/**
* 구글 / 페이스북 로그인 팝업을 띄운다
*/
signInWithPopup(provider) {
this.auth
.signInWithPopup(provider)
.then(result => {
// 로그인 결과값을 DB에 저장
this.saveUserAtDB(result.user)
.then(user => {
// 로그인 성공 시 갤러리 입장
this.enterGallery()
})
})
.catch(error => console.error('로그인 오류', error))
}
/**
* 회원가입 후 user 정보를 indexedDB에 저장한다.
*/
saveUserAtDB(user) {
if (!indexedDB) {
return
}
return new Promise((resolve, reject) => {
var request = indexedDB.open(this.INDEXED_DB_NAME, this.INDEXED_VERSION)
const storeName = this.INDEXED_STORE
request.onupgradeneeded = () => {
const db = request.result
const store = db.createObjectStore(storeName, {keyPath: 'uid'})
}
request.onsuccess = () => {
const db = request.result
const tx = db.transaction([storeName], 'readwrite')
const store = tx.objectStore(storeName)
// 저장된 user.uid를 불러온다.
store.get(user.uid).onsuccess = event => {
const data = event.target.result
console.log('query: ', data)
if (!data) {
// 저장된 uid가 없으면 저장한다.
const newUser = {
uid: user.uid
, email: user.email
, photoURL: user.photoURL ? user.photoURL : ''
, displayName: user.displayName
}
store.put(newUser)
resolve(newUser)
}
resolve(data)
}
}
request.oncomplete = () => {
console.log('트랜잭션 완료')
db.close();
}
request.onerror = error => {
reject(error)
}
})
}
/**
* 갤러리 입장
* 로그인/회원가입/로그인 세션상태 체크 후 갤러리 화면으로 전환함
*/
enterGallery() {
this.$memberWrap.hide()
this.$galleryWrap.show()
}
}
/**
* DOM Content Loaded
*/
document.addEventListener('DOMContentLoaded', () => {
window.photoApp = new PhotoApp();
});
위 코드는 Google 버튼을 눌렀을때 Google 팝업창에서 인증후 User 정보를 indexedDB에 저장하는 로직입니다.
로그인후 Application > IndexedDB > Users에 User정보가 저장됩니다.
Firebase > Authentication > 사용자에 Google 사용자가 저장됩니다.
Facebook 로그인
/**
* PhotoApp class
*/
class PhotoApp {
/**
* 생성자
*/
constructor() {
this.init();
this.initEvent();
}
/**
* 변수할당
*/
init() {
// IndexedDB 정보
this.INDEXED_DB_NAME = 'USER'
this.INDEXED_VERSION = 1
this.INDEXED_STORE = 'Users'
this.auth = firebase.auth()
this.$btnFacebook = $('#btnFacebook')
}
/**
* Event Binding
*/
initEvent() {
this.$btnFacebook.on('click', this.onFacebookClick.bind(this))
}
/**
* Facebook 버튼 눌러서 로그인 / 회원가입
*/
onFacebookClick(e) {
e.preventDefault();
const facebookProvider = new firebase.auth.FacebookAuthProvider()
this.auth
.setPersistence(firebase.auth.Auth.Persistence.SESSION)
.then(this.signInWithPopup.bind(this, facebookProvider))
.catch(error => console.error('인증상태 설정 중 오류' , error))
}
/**
* 구글 / 페이스북 로그인 팝업을 띄운다
*/
signInWithPopup(provider) {
this.auth
.signInWithPopup(provider)
.then(result => {
// 로그인 결과값을 DB에 저장
this.saveUserAtDB(result.user)
.then(user => {
// 로그인 성공 시 갤러리 입장
this.enterGallery()
})
})
.catch(error => console.error('로그인 오류', error))
}
/**
* 갤러리 입장
* 로그인/회원가입/로그인 세션상태 체크 후 갤러리 화면으로 전환함
*/
enterGallery() {
this.$memberWrap.hide()
this.$galleryWrap.show()
}
}
/**
* DOM Content Loaded
*/
document.addEventListener('DOMContentLoaded', () => {
window.photoApp = new PhotoApp();
});
Facebook 로그인 로직입니다.
Facebook 사용자도 등록되었습니다.
이메일 등록 및 이메일 로그인
/**
* PhotoApp class
*/
class PhotoApp {
/**
* 생성자
*/
constructor() {
this.init();
this.initEvent();
}
/**
* 변수할당
*/
init() {
// IndexedDB 정보
this.INDEXED_DB_NAME = 'USER'
this.INDEXED_VERSION = 1
this.INDEXED_STORE = 'Users'
this.auth = firebase.auth()
this.$btnGoogle = $('#btnGoogle')
this.$btnFacebook = $('#btnFacebook')
this.$btnToJoin = $('#btnToJoin')
this.$btnToLogin = $('#btnToLogin')
this.$btnJoin = $('#btnJoin')
this.$btnLogin = $('#btnLogin')
this.$btnLogout = $('#btnLogout')
this.$loginScreen = $('#loginScreen')
this.$joinScreen = $('#joinScreen')
this.$memberWrap = $('#userLoginWrap')
this.$galleryWrap = $('#photoGalleryWrap')
}
/**
* Event Binding
*/
initEvent() {
this.$btnGoogle.on('click', this.onGoogleClick.bind(this))
this.$btnFacebook.on('click', this.onFacebookClick.bind(this))
this.$btnToJoin.on('click', this.onToJoinClick.bind(this))
this.$btnToLogin.on('click', this.onToLoginClick.bind(this))
this.$btnJoin.on('click', this.createEmailUser.bind(this))
this.$btnLogin.on('click', this.onEmailLoginClick.bind(this))
this.$btnLogout.on('click', this.onLogoutClick.bind(this))
// 로그인 세션을 체크함
this.auth.onAuthStateChanged(this.onAuthChange.bind(this));
}
/**
* 인증정보가 변화되면 처리함
*/
onAuthChange(user) {
if (user) {
console.log('user login: ', user)
this.enterGallery()
} else {
console.log('user logout')
//this.setLogout()
}
}
/**
* Google 버튼 눌러서 로그인 / 회원가입
*/
onGoogleClick(e) {
e.preventDefault()
const googleProvider = new firebase.auth.GoogleAuthProvider()
this.auth
.setPersistence(firebase.auth.Auth.Persistence.SESSION)
.then(this.signInWithPopup.bind(this, googleProvider))
.catch(error => console.error('인증상태 설정 중 오류' , error))
}
/**
* Facebook 버튼 눌러서 로그인 / 회원가입
*/
onFacebookClick(e) {
e.preventDefault();
const facebookProvider = new firebase.auth.FacebookAuthProvider()
this.auth
.setPersistence(firebase.auth.Auth.Persistence.SESSION)
.then(this.signInWithPopup.bind(this, facebookProvider))
.catch(error => console.error('인증상태 설정 중 오류' , error))
}
/**
* 구글 / 페이스북 로그인 팝업을 띄운다
*/
signInWithPopup(provider) {
this.auth
.signInWithPopup(provider)
.then(result => {
// 로그인 결과값을 DB에 저장
this.saveUserAtDB(result.user)
.then(user => {
// 로그인 성공 시 갤러리 입장
this.enterGallery()
})
})
.catch(error => console.error('로그인 오류', error))
}
/**
* 이메일로 회원 가입
*/
createEmailUser() {
const userName = $.trim($('#userJoinName').val())
const userEmail = $.trim($('#userJoinEmail').val())
const password = $.trim($('#userJoinPassword1').val())
const repassword = $.trim($('#userJoinPassword2').val())
if (this.validationJoinForm(userName, userEmail, password, repassword)) {
// 회원가입 성공시 DB에 user 정보를 넣음
const cbCreateUserWithEmail = result => {
this.saveUserAtDB(result.user, userName)
.then(user => {
// 이메일 회원가입 성공후 갤러리 입장
this.enterGallery()
})
console.log('이메일 가입 성공: ', result.user)
}
// 이메일로 회원가입 요청
const cbAfterPersistence = () => {
return this.auth.createUserWithEmailAndPassword(userEmail, password)
.then(cbCreateUserWithEmail.bind(this))
.catch(error => {
console.error('이메일 가입 에러: ', error)
switch (error.code) {
case 'auth/email-already-in-use':
alert('이미 사용중인 이메일 입니다.')
break;
case 'auth/invalid-email':
alert('유효하지 않은 메일입니다')
break;
case 'auth/operation-not-allowed':
alert('이메일 가입이 중지되었습니다.')
break;
case 'auth/weak-password':
alert('비밀번호를 6자리 이상 필요합니다')
break;
}
})
}
this.auth.setPersistence(firebase.auth.Auth.Persistence.SESSION)
.then(cbAfterPersistence.bind(this))
.catch(error => console.error('인증 상태 설정 중 에러 발생' , error))
}
}
/**
* 이메일로 로그인
*/
onEmailLoginClick() {
const userEmail = $.trim($('#userLoginEmail').val())
const password = $.trim($('#userLoginPassword').val())
if (this.validationLoginForm(userEmail, password)) {
// 이메일로 로그인 요청
const cbLoginInEmail = () => {
return this.auth.signInWithEmailAndPassword(userEmail, password)
.then(result => {
// 로그인 성공후 갤러리 입장
this.enterGallery()
})
.catch(error => {
console.error('이메일 로그인 에러', error);
switch(error.code){
case 'auth/invalid-email':
alert('유효하지 않은 메일입니다');
break;
case 'auth/user-disabled':
alert('사용이 정지된 유저 입니다.')
break;
case 'auth/user-not-found':
alert('사용자를 찾을 수 없습니다.')
break;
case 'auth/wrong-password':
alert("잘못된 패스워드 입니다.");
break;
}
})
}
this.auth.setPersistence(firebase.auth.Auth.Persistence.SESSION)
.then(cbLoginInEmail.bind(this))
}
}
/**
* 회원가입 후 user 정보를 indexedDB에 저장한다.
*/
saveUserAtDB(user) {
if (!indexedDB) {
return
}
return new Promise((resolve, reject) => {
var request = indexedDB.open(this.INDEXED_DB_NAME, this.INDEXED_VERSION)
const storeName = this.INDEXED_STORE
request.onupgradeneeded = () => {
const db = request.result
const store = db.createObjectStore(storeName, {keyPath: 'uid'})
}
request.onsuccess = () => {
const db = request.result
const tx = db.transaction([storeName], 'readwrite')
const store = tx.objectStore(storeName)
// 저장된 user.uid를 불러온다.
store.get(user.uid).onsuccess = event => {
const data = event.target.result
console.log('query: ', data)
if (!data) {
// 저장된 uid가 없으면 저장한다.
const newUser = {
uid: user.uid
, email: user.email
, photoURL: user.photoURL ? user.photoURL : ''
, displayName: user.displayName
}
store.put(newUser)
resolve(newUser)
}
resolve(data)
}
}
request.oncomplete = () => {
console.log('트랜잭션 완료')
db.close();
}
request.onerror = error => {
reject(error)
}
})
}
/**
* 로그아웃 버튼 클릭
* 로그아웃 하고 로그인 화면으로 전환함
*/
onLogoutClick() {
this.auth.signOut()
this.goToLogin()
}
/**
* 갤러리 입장
* 로그인/회원가입/로그인 세션상태 체크 후 갤러리 화면으로 전환함
*/
enterGallery() {
this.$memberWrap.hide()
this.$galleryWrap.show()
}
/**
* 로그인 페이지로 전환
* 로그아웃 처리후 로그인 화면으로 전환함
*/
goToLogin() {
this.$memberWrap.show()
this.$galleryWrap.hide()
}
/**
* 이메일 회원가입 화면으로 전환
*/
onToJoinClick(e) {
e.preventDefault()
this.$loginScreen.hide()
this.$joinScreen.show()
}
/**
* 로그인 화면으로 전환
*/
onToLoginClick(e) {
e.preventDefault()
this.$loginScreen.show()
this.$joinScreen.hide()
}
/**
* email 로그인 폼 유효성 검사
*/
validationLoginForm(userEmail, password) {
if (!this.emailCheck(userEmail)) {
alert('이메일 형식에 맞지 않습니다.')
return false
}
if (!password) {
alert('패스워드를 입력하세요.')
return false
}
return true
}
/**
* email 가입 폼 유효성 검사
*/
validationJoinForm(userName, userEmail, password, repassword) {
if (!userName) {
alert('이름은 필수입니다.')
return false
}
if (!this.emailCheck(userEmail)) {
alert('이메일 형식에 맞지 않습니다.')
return false
}
if (!password || !repassword) {
alert('패스워드를 입력하세요.')
return false
}
if (password != repassword) {
alert('패스워드가 동일하지 않습니다.')
return false
}
return true
}
/**
* 이메일 형식 체크
*/
emailCheck(email) {
if (/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(email)) {
return true;
}
return false;
}
}
/**
* DOM Content Loaded
*/
document.addEventListener('DOMContentLoaded', () => {
window.photoApp = new PhotoApp();
});
이메일 회원가입, 이메일 로그인 처리된 최종 코드입니다.
크롬 Console에서 회원가입시 로그를 확인 할 수 있습니다.
Email 회원도 등록되었습니다.
로그아웃하고 다시 로그인 해봅니다.
'Frontend > Firebase' 카테고리의 다른 글
[Firebase] GCP 리소스 위치 (2) | 2020.05.14 |
---|---|
[Firebase] 도메인 연결 - Cafe24 서브도메인 연결하기 (3) | 2020.02.06 |
[Firebase] Storage에 사진 파일 올리기 (0) | 2019.09.24 |
[Firebase Status Dashboard] Firebase 프로젝트나 앱이 생성되지 않을때... (0) | 2019.07.26 |
[Firebase] Python Flask 웹 서비스 (1) | 2019.07.21 |