5년 이상 전

간단한 메모장 만들기 4 - Auth

이번시간에는 파이어베이스를 이용한 로그인 연동, 회원가입, 로그아웃을 해보겠습니다.

https://console.firebase.google.com

프로젝트 추가 버튼을 클릭하세요

해당 프로젝트로 들어가시면 정 가운데 세번째 버튼에 웹 앱으로 배포하기라는 버튼이 있을겁니다. 클릭해주세요.

<script src="https://www.gstatic.com/firebasejs/4.1.3/firebase.js"></script>
<script>
  // Initialize Firebase
  var config = {
    apiKey: "YOUR_API_KEY",
    authDomain: "YOUR_PROJECT_NAME-YOUR_PROJCET_NUMBER.firebaseapp.com",
    databaseURL: "https://YOUR_PROJECT_NAME-YOUR_PROJCET_NUMBER.firebaseio.com",
    projectId: "YOUR_PROJECT_NAME-YOUR_PROJCET_NUMBER",
    storageBucket: "YOUR_PROJECT_NAME-YOUR_PROJCET_NUMBER.appspot.com",
    messagingSenderId: "12345678"
  };
  firebase.initializeApp(config);
</script>

config 변수 부분을 복사해주세요 딴건 필요없답니다.

아이오닉 프로젝트에 추가하기

Ionic에서 지원하는 파이어베이스 패키지들을 인스톨하여주세요.

npm install --save angularfire2 firebase

그 다음에 루트 모듈 ( 보통은 app.module.ts )에 파이어베이스 모듈을 추가할게요.

변경 후

...

import { AngularFireModule } from 'angularfire2'; // 파이어베이스 루트 모듈입니다.
import { AngularFireDatabaseModule } from 'angularfire2/database'; // 파이어베이스 데이터베이스 모듈입니다.
import { AngularFireAuthModule } from 'angularfire2/auth'; // 파이버베이스 인증 모듈입니다.

...

// 방금 복사했던 config를 가져오시면 됩니다.
export const firebaseConfig = {
  apiKey: "YOUR_API_KEY",
  authDomain: "YOUR_PROJECT_NAME-YOUR_PROJCET_NUMBER.firebaseapp.com",
  databaseURL: "https://YOUR_PROJECT_NAME-YOUR_PROJCET_NUMBER.firebaseio.com",
  projectId: "YOUR_PROJECT_NAME-YOUR_PROJCET_NUMBER",
  storageBucket: "YOUR_PROJECT_NAME-YOUR_PROJCET_NUMBER.appspot.com",
  messagingSenderId: "12345678"
};


@NgModule({
  declarations: [AppComponent],
  imports: [
    BrowserModule,
    HttpModule,
    TranslateModule.forRoot({
      loader: {
        provide: TranslateLoader,
        useFactory: HttpLoaderFactory,
        deps: [Http]
      }
    }),
    IonicModule.forRoot(AppComponent, {
      preloadModules: true
    }),
    IonicStorageModule.forRoot(),
    // 설정파일을 인자로 넘겨주어 앱을 초기화합니다.
    AngularFireModule.initializeApp(firebaseConfig),
    AngularFireDatabaseModule,
    AngularFireAuthModule,
    ...
  ],
  entryComponents: [AppComponent],
  bootstrap: [IonicApp],
  providers: []
})
export class AppModule { }

로그인 서비스 활성화시키기

파이어베이스에 들어가신 후

Authentication -> 로그인 방법을 클릭하신 후

이메일 로그인 방식과 페이스북 로그인 방식을 활성화해주세요

인증서비스

인증 서비스파일 만들기.

$ ionic g provider auth-manager

src/pages/memo-manager/memo-manager.ts

import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import { AngularFireAuth } from 'angularfire2/auth';
import { Observable } from 'rxjs/Observable';
import * as firebase from 'firebase/app';

import 'rxjs/add/operator/map';

@Injectable()
export class AuthManagerProvider {

  userInfo: firebase.User = null;
  authState: Observable<firebase.User>

  constructor(
    public http: Http, 
    public afAuth: AngularFireAuth) {
    this.initAuth();
  }

  initAuth() {
    this.authState = this.afAuth.authState;
    this.authState.subscribe(
      (user: firebase.User) => {
        if(user) {
          this.setUserInfo(user);
        } else {
          this.setUserInfo(null);
        }
      }
    )
  }

  getAuthState(): Observable<firebase.User> {
    return this.authState;
  }

  getUserInfo() {
    return this.userInfo;
  }

  setUserInfo(userInfo: firebase.User) {
    this.userInfo = userInfo;
  }

  loginUser(email: string, password: string) {
    return this.afAuth.auth.signInWithEmailAndPassword(email, password);
  }

  signUpUser(email: string, password: string) {
    return this.afAuth.auth.createUserWithEmailAndPassword(email, password)
  }

  resetPassword(email: string) {
    return this.afAuth.auth.sendPasswordResetEmail(email);
  }

  logoutUser() {
    return this.afAuth.auth.signOut();
  }
}

로그인상태 여부에따라 최초 로딩페이지 바꿔주기

src/app/app/component.ts

import { Component } from '@angular/core';
import { Platform } from 'ionic-angular';
import { StatusBar } from '@ionic-native/status-bar';
import { SplashScreen } from '@ionic-native/splash-screen';
import { AuthManagerProvider } from './../providers/auth-manager/auth-manager';

import { SignInPage } from './../pages/sign-in/sign-in';
import { MemoListPage } from './../pages/memo-list/memo-list';

@Component({
  templateUrl: 'app.html'
})

export class MyApp {
  rootPage:any;

  constructor(
    platform: Platform, 
    statusBar: StatusBar, 
    splashScreen: SplashScreen,
    authManager: AuthManagerProvider,
  ) {
    platform.ready().then(() => {
      // Okay, so the platform is ready and our plugins are available.
      // Here you can do any higher level native things you might need.
      statusBar.styleDefault();
      splashScreen.hide();
    });
    authManager.getAuthState().subscribe((user => {
      if(user)
        this.rootPage = MemoListPage;
      else 
        this.rootPage = SignInPage;
    }));
  }  
}

이제 로그인, 회원가입, 로그아웃만 구현하면 됩니다.

회원가입 페이지

src/pages/sign-up/sign-up.module.ts

import { NgModule } from '@angular/core';
import { IonicPageModule } from 'ionic-angular';
import { SignUpPage } from './sign-up';
import { FormsModule } from '@angular/forms';

@NgModule({
  declarations: [
    SignUpPage,
  ],
  imports: [
    IonicPageModule.forChild(SignUpPage),
    FormsModule
  ],
  exports: [
    SignUpPage
  ]
})
export class SignUpPageModule {}

src/pages/sign-up/sign-up.ts

import { Component } from '@angular/core';
import { IonicPage, NavController, NavParams } from 'ionic-angular';
import { AuthManagerProvider } from '../../providers/auth-manager/auth-manager';
import { LoadingController, AlertController } from 'ionic-angular';

@IonicPage()
@Component({
  selector: 'page-sign-up',
  templateUrl: 'sign-up.html',
})
export class SignUpPage {

  emailAddress: string = '';
  password: string = '';

  constructor(
    public navCtrl: NavController, 
    public navParams: NavParams,
    public authManager: AuthManagerProvider,
    public loadingCtrl: LoadingController,
    public alertCtrl: AlertController,
  ) {
  }
  
  onClickDDalpange() {
    window.location.href = "https://ddalpange.github.io";
  }
  
  onClickSignUp() {
    let loader = this.loadingCtrl.create({
      content: '회원가입 중입니다 ..'
    });
    loader.present();
 
    this.authManager.signUpUser(this.emailAddress, this.password)
    .then(user => {
      console.log('성공!', user);
      loader.dismiss();
      const alert = this.getSuccessAlert();
      alert.present();
    })
    .catch(err => { 
      loader.dismiss();
      const alert = this.getFailAlert(err.message);
      alert.present();
    });
  }

  getSuccessAlert() {
    return this.alertCtrl.create({
      title: 'success!!',
      subTitle: '회원가입에 성공하였습니다.',
      buttons: [{
        text: '확인',
      }]
    });
  }

  getFailAlert(message: string) {
    return this.alertCtrl.create({
      title: 'failed..',
      subTitle: message,
      buttons: [{
        text: '확인'
      }]
    });
  }
  
  onClickNavBack() {
    this.navCtrl.pop();
  }
}

src/pages/sign-up/sign-up.html

<ion-content padding>
   <div class="image-wrap">
    <img src="/images/gyul.png" 
      (click)="onClickDDalpange()"/>
    <p>달팽이의 메모 앱</p>
    <ion-list>
      <ion-item>
        <ion-input type="email" placeholder="이메일" [(ngModel)]="emailAddress" (keyup.enter)="onClickSignUp()"></ion-input>
      </ion-item>
      <ion-item>
        <ion-input type="password" placeholder="비밀번호" [(ngModel)]="password" (keyup.enter)="onClickSignUp()"></ion-input>
      </ion-item>
    </ion-list>
  </div>
  <button ion-button block color="light" (click)="onClickSignUp()">가입하기</button>
  <button ion-button block color="danger" (click)="onClickNavBack()">뒤로가기</button>
</ion-content>

로그인 페이지

src/pages/sign-in/sign-in.module.ts

import { FormsModule } from '@angular/forms';
import { NgModule } from '@angular/core';
import { IonicPageModule } from 'ionic-angular';
import { SignInPage } from './sign-in';

@NgModule({
  declarations: [
    SignInPage,
  ],
  imports: [
    IonicPageModule.forChild(SignInPage),
    FormsModule
    
  ],
  exports: [
    SignInPage
  ]
})
export class SignInPageModule {}

src/pages/sign-in/sign-in.ts

import { Component } from '@angular/core';
import { IonicPage, NavController, NavParams, AlertController, LoadingController } from 'ionic-angular';

import { SignUpPage } from './../sign-up/sign-up';
import { MemoListPage } from './../memo-list/memo-list';
import { AuthManagerProvider } from '../../providers/auth-manager/auth-manager';

@IonicPage()
@Component({
  selector: 'page-sign-in',
  templateUrl: 'sign-in.html',
})

export class SignInPage {
  
  emailAddress: string = '';
  password: string = '';

  constructor(
    public navCtrl: NavController, 
    public navParams: NavParams,
    public alertCtrl: AlertController,
    public loadingCtrl: LoadingController,
    public authManager: AuthManagerProvider
  ) {}

  onClickDDalpange() {
    window.location.href = "https://ddalpange.github.io";
  }

  onClickEmailLogIn() {
    let loader = this.loadingCtrl.create({
      content: '로그인 중입니다 ..'
    });

    loader.present();

    this.authManager.loginUser(this.emailAddress, this.password)
      .then(user => {
      console.log('성공!', user);
      loader.dismiss();
      this.navCtrl.setRoot(MemoListPage);
    })
    .catch(err => { 
      console.error('실패!', err);
      loader.dismiss();
      const alert = this.getFailAlert(err.message);
      alert.present();
    });;
  }

  onClickFacebookLogin() {
    const alert = this.getFailAlert('미완성 기능입니다.');
    alert.present();
  }

  getFailAlert(message: string) {
    return this.alertCtrl.create({
      title: 'failed..',
      subTitle: message,
      buttons: [{
        text: '확인'
      }]
    });
  }

  onClickSignUp() {
    this.navCtrl.push(SignUpPage);
  }
}

src/pages/sign-in/sign-in.html

<ion-content padding>
  <div class="image-wrap">
    <img src="/images/gyul.png" 
      (click)="onClickDDalpange()"/>
    <p>달팽이의 메모 앱</p>
    <ion-list>
      <ion-item>
        <ion-input type="email" placeholder="이메일" [(ngModel)]="emailAddress" (keyup.enter)="onClickEmailLogIn()"></ion-input>
      </ion-item>
      <ion-item>
        <ion-input type="password" placeholder="비밀번호" [(ngModel)]="password" (keyup.enter)="onClickEmailLogIn()"></ion-input>
      </ion-item>
    </ion-list>
  </div>
  <button ion-button block color="light" (click)="onClickEmailLogIn()">이메일 로그인</button>
  <button ion-button block color="primary" (click)="onClickFacebookLogin()">페이스북 로그인</button>
  <p class="sign-up-text" (click)="onClickSignUp()">계정이 없으신가요?</p>
</ion-content>

로그아웃 기능(리스트 페이지)

src/pages/memo-list/memo-list.module.ts

import { FormsModule } from '@angular/forms';
import { NgModule } from '@angular/core';
import { IonicPageModule } from 'ionic-angular';
import { MemoListPage } from './memo-list';

@NgModule({
  declarations: [
    MemoListPage,
  ],
  imports: [
    IonicPageModule.forChild(MemoListPage),
    FormsModule
  ],
  exports: [
    MemoListPage
  ]
})
export class MemoListPageModule {}

src/pages/memo-list/memo-list.ts

import { AuthManagerProvider } from './../../providers/auth-manager/auth-manager';
import { FirebaseListObservable } from 'angularfire2/database';
import { Memo } from './../../models/memo/memo.interface';
import { Component, OnInit } from '@angular/core';
import { IonicPage, NavController, NavParams, LoadingController, ActionSheetController } from 'ionic-angular';

import { MemoCreatePage } from './../memo-create/memo-create';
import { MemoDetailPage } from './../memo-detail/memo-detail';

import { MemoManagerProvider } from './../../providers/memo-manager/memo-manager';
@IonicPage()

@Component({
  selector: 'page-memo-list',
  templateUrl: 'memo-list.html',
})

export class MemoListPage {

  searchKeyword: string = '';
  memoList: Memo = [];

  constructor(
    public navCtrl: NavController,
    public navParams: NavParams,
    public loadingCtrl: LoadingController,
    public actionSheetCtrl: ActionSheetController,
    public authManager: AuthManagerProvider,
    public memoManager: MemoManagerProvider) {
  }
 
  ngOnInit() {
    this.memoList = this.memoManager.getMemoList();
  }

  filterMemo(memo: Memo): boolean {
    return memo.title.includes(this.searchKeyword) || memo.title.includes(this.searchKeyword);
  }

  onClickViewMemoDetail(memo: Memo) {
    this.navCtrl.push(MemoDetailPage, { memo: memo });
  }
  
  onClickCreateMemo() {
    this.navCtrl.push(MemoCreatePage);
  }

  onClickMoreOption() {
    const actionSheet = this.actionSheetCtrl.create({
      buttons: [
        {
          text: 'Logout',
          role: 'destructive',
          handler: () => {
            this.authManager.logoutUser();
          }
        }, {
          text: 'Cancel',
          role: 'cancel'
        }
      ]
    });
    actionSheet.present();
  }
}

src/pages/memo-list/memo-list.html

<ion-header>
  <ion-navbar color="primary">
    <ion-searchbar [(ngModel)]="searchKeyword"></ion-searchbar>
    <ion-buttons end>
      <button ion-button icon-only (click)="onClickMoreOption()">
        <ion-icon name="more">
        </ion-icon>
      </button>
    </ion-buttons>
  </ion-navbar>
</ion-header>
<!-- 콘텐츠 내용... -->

로그인, 로그아웃, 회원가입 총 3가지 기능을 완성하였습니다.

다음 포스트 에서는 파이어베이스의 리얼타임 데이터베이스를 이용해 데이터를 관리해볼게요!


참고 링크