본문 바로가기

Ionic 3

[4] Ionic & Firebase 로그인 기능 구현


이번 포스팅에서는 Ionic Framework와 Firebase의 이메일 인증 서비스를 활용하여 로그인 기능을 구현하는 방법을 소개하고자 합니다.


Firebase Console에서 이메일 로그인을 위한 설정을 한 후, 사용자 정보를 입력받아 등록하는 등록 페이지를 구성하고 등록된 정보를 이용하여 로그인하는 페이지를 구현하는 순서로 진행하도록 할 것입니다.




Firebase 로그인 방법 설정

Firebase Console로 이동하여 로그인 방법을 이메일/비밀번호 방식으로 설정하도록 합니다. 



Authentication 메뉴에서 '로그인 방법' 카테고리로 이동 하여 '이메일/비밀번호' 선택한 후 사용설정을 황성화 시켜주고 저장합니다. 


본격적으로 로그인을 위한 화면 구성및 로직을 구현하고록 하겠습니다. ionic generate 명령어를 통해 login폴더 및 하위에 ts, html, scss 파일을 생성 할 수 있습니다.



Tab 추가하기

로그인 기능을 구현하기 전에 side menu 기반으로 생성했던 프로젝트에 Tab을 추가 하도록 하겠습니다. 

$ionic g page login

ionic generate page를 통해 등록한 구성요소들은 자동으로 최상위 Module에 등록되어집니다.

src/pages/tabs/tabs.html

1
2
3
4
5
6
<ion-tabs>
  <!-- Indicates with tabsPage should handle each tab here -->
  <ion-tab [root]="tab1Root" tabTitle="Home" tabIcon="home"></ion-tab>
  <ion-tab [root]="tab2Root" tabTitle="Gallery" tabIcon="photos"></ion-tab>
  <ion-tab [root]="tab3Root" tabTitle="Profile" tabIcon="person"></ion-tab>
</ion-tabs>
cs


src/pages/tabs/tabs.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import { Component } from '@angular/core';
 
import { HomePage } from '../home/home';
import { ListPage } from '../list/list';
import { ProfilePage } from '../profile/profile';
 
@Component({
  templateUrl: 'tabs.html'
})
export class TabsPage {
  // this tells the tabs component which Pages
  // should be each tab's root Page
  tab1Root: any = HomePage;
  tab2Root: any = ListPage;
  tab3Root: any = ProfilePage;
 
  constructor() {
 
  }
}
cs


src/app/app.html

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
import { Component, ViewChild } from '@angular/core';
import { Nav, Platform } from 'ionic-angular';
import { StatusBar } from '@ionic-native/status-bar';
import { SplashScreen } from '@ionic-native/splash-screen';
import { AngularFireAuth } from 'angularfire2/auth';
 
import { TabsPage } from '../pages/tabs/tabs';
import { LoginPage } from '../pages/login/login';
 
@Component({
  templateUrl: 'app.html'
})
export class MyApp {
  @ViewChild(Nav) nav: Nav;
 
  rootPage: any = TabsPage;
 
  pages: Array<{ title: string, component: any }>;
 
  constructor(public platform: Platform,
    private afAuth: AngularFireAuth,
    public statusBar: StatusBar,
    public splashScreen: SplashScreen) {
    this.initializeApp();
    // used for an example of ngFor and navigation
    this.pages = [
      { title: 'login', component: LoginPage }
    ];
  }
  
  initializeApp() {
    this.afAuth.authState.subscribe(auth => {
      if (auth) {
        this.rootPage = TabsPage;
      } else {
        this.rootPage = LoginPage;
      }
    });
 
    this.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.
      this.statusBar.styleDefault();
      this.splashScreen.hide();
    });
  }
 
  openPage(page) {
    // Reset the content nav to have just this page
    // we wouldn't want the back button to show in this scenario
    this.nav.setRoot(page.component);
  }
}
 
cs

src/app/app.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<ion-menu [content]="content">
    <ion-header>
        <ion-toolbar>
            <ion-title>Menu</ion-title>
        </ion-toolbar>
    </ion-header>
 
    <ion-content>
        <ion-list>
            <button menuClose ion-item *ngFor="let page of pages" (click)="openPage(page)">
                {{page.title}}
            </button>
        </ion-list>
    </ion-content>
</ion-menu>
 
<!-- Disable swipe-to-go-back because it's poor UX to combine STGB with side menus -->
<ion-nav [root]="rootPage" #content swipeBackEnabled="false"></ion-nav>
cs


로그인 기능 구현

(1) model 구성

src/pages/models/user.ts
1
2
3
4
export class User {
    email: string;
    password: string;
}
cs

(2) login page생성

$ ionic g page login


src/pages/login/login.html

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
<ion-header>
  <ion-navbar>
    <button ion-button menuToggle>
      <ion-icon name="menu"></ion-icon>
    </button>
    <ion-title>Login</ion-title>
  </ion-navbar>
</ion-header>
 
<ion-content padding primary-color-text>
  <ion-grid>
    <ion-row>
      <ion-card>
        <ion-item>
          <ion-label floating>Email Address</ion-label>
          <ion-input type="text" [(ngModel)]="user.email"></ion-input>
        </ion-item>
        <ion-item>
          <ion-label floating>Password</ion-label>
          <ion-input type="password" [(ngModel)]="user.password"></ion-input>
        </ion-item>
        <button ion-button (click)="signin();">Login</button>
        <button ion-button color="secondary" (click)="signup();">Register</button>
      </ion-card>
    </ion-row>
  </ion-grid>
</ion-content>
cs


src/pages/login/login.ts

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import { Component } from '@angular/core';
import { NavController, LoadingController, Loading } from 'ionic-angular';
import { AngularFireAuth } from 'angularfire2/auth';
 
import { RegisterPage } from '../register/register';
import { HomePage } from '../home/home';
import { AuthProvider } from '../../providers/auth/auth';
 
import { User } from '../models/user';
 
@Component({
  selector: 'page-login',
  templateUrl: 'login.html',
})
export class LoginPage {
 
  public userId: string;
  _firstName: String;
  _gender: String;
  _lastName: String;
  _name: String;
  _data: any;
  user: any = {} as User;
 
  constructor(public navCtrl: NavController,
    private loadingCtrl: LoadingController,
    private authService: AuthProvider) {
  }
 
  signin(user: User) {
    let loading = this.loadingCtrl.create({
      content: 'Loading...'
    });
    loading.present();
 
    this.authService.login(this.user)
      .then(auth => {
        loading.dismiss();
        this.navCtrl.setRoot(HomePage);
      })
      .catch(err => {
        loading.dismiss();
        alert(JSON.stringify(err));
      });
  }
 
  signup() {
    this.navCtrl.push(RegisterPage);
  }
 
  ionViewDidLoad() {
    console.log('ionViewDidLoad LoginPage');
  }
 
}
 
cs


src/providers/auth/auth.ts

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
import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import { AngularFireAuth } from 'angularfire2/auth';
 
import * as firebase from 'firebase/app';
import 'rxjs/add/operator/map';
 
import { User } from '../../pages/models/user';
 
 
 
@Injectable()
export class AuthProvider {
 
  constructor(public http: Http,
    public angularFireAuth: AngularFireAuth) {
  }
 
  login(user: User): firebase.Promise<any> {
    return this.angularFireAuth.auth.signInWithEmailAndPassword(user.email, user.password);
  }
addUser(user): firebase.Promise<any> {
return this.angularFireAuth.auth.createUserWithEmailAndPassword(user.email, user.password);
{
}


위와 같이 login관련 api등록을 위한 auth.ts를 구성해줍니다. 해당 auth.ts 는 최상위 모듈인 app.modult.ts에 import 및 providers에 등록시켜주어야 합니다.


src/app/login/login.ts

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
//Angular Module
import { BrowserModule } from '@angular/platform-browser';
import { HttpModule } from '@angular/http';
import { ErrorHandler, NgModule } from '@angular/core';
 
//Ionic Module
import { IonicApp, IonicErrorHandler, IonicModule } from 'ionic-angular';
import { StatusBar } from '@ionic-native/status-bar';
import { SplashScreen } from '@ionic-native/splash-screen';
 
//Firebase Module
import { AngularFireAuthModule } from 'angularfire2/auth';
import { AngularFireDatabaseModule } from 'angularfire2/database';
import { AngularFireModule } from 'angularfire2';
 
//Pages Component
import { MyApp } from './app.component';
import { TabsPage } from '../pages/tabs/tabs';
import { HomePage } from '../pages/home/home';
import { ListPage } from '../pages/list/list';
import { LoginPage } from '../pages/login/login';
import { RegisterPage } from '../pages/register/register';
 
//Firebase auth key
import { FIREBASE_CONFIG } from './config/app.firebase.config';
 
//Service
import { AuthProvider } from '../providers/auth/auth';
 
@NgModule({
  declarations: [
    MyApp,
    TabsPage,
    HomePage,
    ListPage,
    LoginPage,
RegisterPage
  ],
  imports: [
    BrowserModule,
    HttpModule,
    AngularFireDatabaseModule,
    AngularFireAuthModule,
    AngularFireModule.initializeApp(FIREBASE_CONFIG),
    IonicModule.forRoot(MyApp)
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp,
    TabsPage,
    HomePage,
    ListPage,
    LoginPage,
RegisterPage
  ],
  providers: [
    StatusBar,
    SplashScreen,
    { provide: ErrorHandler, useClass: IonicErrorHandler }
    AuthProvider
  ]
})
export class AppModule {
}
 



등록 기능 구현

로그인 화면에 이어 사용자 회원가입을 위한 페이지를 생성하여 작성합니다.

$ ionic g page resister


src/app/resister/resister.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<ion-header>
  <ion-navbar>
    <ion-title>Register</ion-title>
  </ion-navbar>
</ion-header>
 
<ion-content padding>
  <ion-item>
    <ion-label floating>Email Address</ion-label>
    <ion-input type="text" [(ngModel)]="user.email"></ion-input>
  </ion-item>
  <ion-item>
    <ion-label floating>Password</ion-label>
    <ion-input type="password" [(ngModel)]="user.password"></ion-input>
  </ion-item>
  <button ion-button color="primary" (click)="signup();">Register</button>
  <button ion-button full clear color="light" (click)="goback()">Go Back</button>
</ion-content>
cs


src/app/resister/resister.ts

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
import { Component } from '@angular/core';
import { NavController, LoadingController } from 'ionic-angular';
import { AngularFireAuth } from 'angularfire2/auth';
 
import { LoginPage } from '../login/login';
import { AngularFireDatabase, FirebaseListObservable } from 'angularfire2/database';
import { AuthProvider } from '../../providers/auth/auth';
 
import { User } from '../models/user';
 
@Component({
    selector: 'page-register',
    templateUrl: 'register.html',
})
export class RegisterPage {
 
    user: any = {} as User;
 
    constructor(public navCtrl: NavController,
        private loadingCtrl: LoadingController,
        private authService: AuthProvider) {
        // Firebase database
    }
 
    async signup() {
        let loading = this.loadingCtrl.create({
            content'Loading...'
        });
        loading.present();
 
        try {
            await this.authService.addUser(this.user).then(
                (user: any) => {
                    console.log(user);
                    loading.dismiss();
                }, (error) => {
                    loading.dismiss();
                    let errortoast = this.loadingCtrl.create({
                        content'Register Error!',
                        duration: 2000
                    });
                    errortoast.present();
                });
 
        } catch (err) {
            console.error(err);
            loading.dismiss();
        }
    }
 
    goBack() {
        this.navCtrl.setRoot(LoginPage);
    }
 
    ionViewDidLoad() {
        console.log('ionViewDidLoad RegisterPage');
    }
 
}
 
cs



로그인, 등록 페이지 확인

$ ionic serve -lab



Firebase Console 사용자 확인

Firebase Console - Authentication - 사용자 탭에서 가입한 사용자를 확인할 수 있습니다.