[Angular] Angular와 Firebase 연동(Firebase Login)

2021. 2. 2. 00:26WEB.DEV/Angular

반응형

이전에 Angular와 Firebase를 연동하는 것을 해보았습니다.

자세한 내용은 이전 포스팅을 참고해주세요.

 

Angualr와 Firebase 연동

Angular와 Firebase는 Angualrfire를 이용하여 쉽게 연동을 할수 있습니다. 먼저 Angular CLI를 이용하여 새로운 Angular 프로젝트를 생성합니다. Angulre CLI 설치는 이전 포스팅을 참고해주세요. Angular CLI 설..

dev-bak.tistory.com


 

이번에는 Firebase 인증(Authentication)을 이용하여 로그인을 구현해보겠습니다.

 

여기서는 간단하게 Email과 Google 로그인을 해볼겁니다.

 

먼저 Firebase 콘솔에 이전에 생성한 프로젝트에서 로그인 사용을 허용해줘야합니다.

Authentication(인증) 메뉴를 선택해줍니다.

그리고 시작하기를 클릭해줍니다.

그러면 아래와 같이 Firebase에서 지원을 하는 로그인 항목들을 확인할 수 있습니다.

원하는 로그인 방법에 마우스를 올리면 아래와 같이 구성 수정 메뉴가 보이게 됩니다.

이메일/비밀번호 로그인 항목에 구성 수정을 클릭하게 되면 아래와 같이 이메일/비밀번호 항목에 대한 메뉴가 나타납니다.

제일 위에 있는 사용 설정은 이메일/비밀번호를 사용해서 로그인을 하는 방식을 사용할 것인지 설정을 하는 것이고, 아래에 있는 이메일 링크 비밀번호가 없는 로그인은 비밀번호 없이 이메일로 인증 메일을 전송해서 메일 확인을 통해서 로그인하는 방식을 지원할 것인지 설정하는 것입니다.

저처럼 이메일/비밀번호로만 로그인을 하게 하기 위해서 처음에 있는 사용 설정만 허용을 하시고 저장을 하시면 됩니다.

구글 구성 수정을 클릭하면 아래와 같은 메뉴가 나오고 사용 설정은 구글로 로그인을 가능하게 할 것인지 설정을 하는 것이고, 프로젝트의 공개 이름은 구글 로그인을 할때 보여지는 프로젝트 이름입니다. 그리고 프로젝트 지원 이메일의 경우는 자신의 이메일을 선택하면 됩니다.

그리고 저장을 하게 되면 구글 로그인까지 설정이 완료됩니다.


 

이제 콘솔에서 할 설정이 끝이 났으니 코드를 작성해보겠습니다.

 

먼저 이전 포스팅에서 작성을 했던 FirebaseModule에 Firebase Authentication을 사용하기 위해 AngularFireAuthModule을 추가해줍니다.

 

// firebase.module.ts
import {NgModule} from '@angular/core';
import {AngularFireModule} from '@angular/fire';

import {environment} from '../environments/environment';
import {AngularFireAuthModule} from '@angular/fire/auth';  // Firebase Authentication 사용을 위한 모듈

@NgModule({
  imports: [
    AngularFireModule.initializeApp(environment.firebaseConfig)
  ],
  exports: [
    AngularFireModule,
    AngularFireAuthModule
  ]
})
export class FirebaseModule {
}

 

그리고 로그인 뷰를 위한 LoginComponent를 생성해줍니다.

# skipTests는 테스트 코드를 생성할 건지 생성을 하지 않을 건지 여부를 설정
# -m(--module)은 어느 모듈에 해당 컴포넌트를 추가할 것인지를 설정 app으로 하게 되면 기본 모듈인 app.module.ts에 추가됨
$ ng g c login --skipTests true -m app

 

 

그리고 회원가입을 위한 SignUpComponent를 생성해줍니다.

$ ng g c sign-up --skipTests true -m app

 

그리고 로그인이 완료 되었을 때 임시로 보여줄 HomeComponent를 생성해줍니다.

$ ng g c home --skipTests true -m app

 

그리고 해당 Component들을 보여주기 위해 Router를 설정하겠습니다.

먼저 app.component.html에 있는 프로젝트 생성시 기본적으로 작성되어 있는 코드를 모두 삭제를 하고 router-outlet를 작성해줍니다.

router-outlet은 URL에 따라 RouterModule에 설정된 Component를 보여줍니다.

(자세한 내용은 나중에 포스팅을 하도록 하겠습니다.)

// app.component.html
<router-outlet></router-outlet>

그리고 URL에 따른 Component 설정을 하기 위해 src > app > app-router.module.ts를 수정합니다.

// app-routing.module.ts
import {NgModule} from '@angular/core';
import {Routes, RouterModule} from '@angular/router';

import {LoginComponent} from './login/login.component';
import {SignUpComponent} from './sign-up/sign-up.component';
import {HomeComponent} from './home/home.component';

const routes: Routes = [
  {path: '', component: LoginComponent}, // /일 경우 LoginComponent를 보여줌
  {path: 'sign-up', component: SignUpComponent},  // /sign-up일 경우 SignUpComponent를 보여줌
  {path: 'home', component: HomeComponent}  // /home일 경우 HomeComponent를 보여줌
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule {
}

 

그리고 로그인과 회원가입을 처리할 AuthService를 생성해줍니다.

$ ng g s services/auth --skipTests true

 

먼저 로그인 처리를 하기 위한 AuthService를 작업하겠습니다.

여기서는 이메일과 비밀번호를 이용한 사용자 생성과 로그인 그리고 구글을 이용한 로그인을 작성했습니다.

각 함수에서는 firebase.auth.UserCredential을 Promise로 반환합니다.

// services/auth.service.ts
import {Injectable} from '@angular/core';
import {AngularFireAuth} from '@angular/fire/auth';  // Firebase Authentication
import firebase from 'firebase';

@Injectable({
  providedIn: 'root'  // root, any, platform이 있는데 여기서는 기본으로 되어 있는 root를 사용
})
export class AuthService {

  constructor(
    private afAuth: AngularFireAuth
  ) {
  }

  // 이메일과 비밀번호를 이용한 사용자 생성
  signUpWithEmailAndPassword(email: string, password: string): Promise<firebase.auth.UserCredential> {
    return this.afAuth.createUserWithEmailAndPassword(email, password);
  }

  // 이메일과 비밀번호를 이용한 로그인
  loginWithEmailAndPassword(email: string, password: string): Promise<firebase.auth.UserCredential> {
    return this.afAuth.signInWithEmailAndPassword(email, password);
  }

  // 구글을 이용한 로그인
  loginWithGoogle(): Promise<firebase.auth.UserCredential> {
    const provider = new firebase.auth.GoogleAuthProvider();
    provider.addScope('https://www.googleapis.com/auth/contacts.readonly');
    firebase.auth().languageCode = 'kr';   // 언어를 한국어로
    provider.setCustomParameters({
      login_hint: 'user@example.com',
      // 구글 로그인시 항상 계정을 선택하도록 추가하지 않으면 대표 계정 혹은 마지막으로 로그인한 계정으로 자동 로그인됨
      prompt: 'select_account'
    });
    return this.afAuth.signInWithPopup(provider);
  }
}

 

로그인과 회원가입을 위한 Service도 준비가 되었으니 로그인과 회원가입 Component를 작성해보겠습니다.

 

먼저 로그인 Component 입니다.

이메일과 비밀번호 입력을 위해서 FormBuilder를 이용하여 FormGroup를 생성하고 AuthService의 loginWithEmailAndPassword와 loginWithGoogle를 연결하는 함수를 만들고 로그인 성공 시 HomeComponent로 이동하기 위해 goHome 함수를 만들어 router.navigate(['home']) 해주었습니다.

// login.component.ts
import {Component, OnInit} from '@angular/core';
import {FormBuilder, FormControl, Validators} from '@angular/forms';  // 이메일과 비밀번호 입력을 위한 Forms
import {Router} from '@angular/router';  // 페이지 이동을 위한 Router
import {AuthService} from '../services/auth.service';  // 로그인과 회원가입을 위해 생성한 AuthService

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.sass']
})
export class LoginComponent implements OnInit {
  // 이메일과 비밀번호 FormGroup 생성
  formGroup = this.formBuilder.group({
    email: this.formBuilder.control('', [
      Validators.email,  // 이메일 형식이 맞는지 확인
      Validators.required  // 이메일이 입력되었는지 확인
    ]),
    password: this.formBuilder.control('', [
      Validators.required,  // 비밀번호가 입력되었는지 확인
      Validators.minLength(6)  // 비밀번호가 최소 6자 이상 입력되었는지 확인
    ])
  });

  get email(): FormControl {
    return this.formGroup.get('email') as FormControl;
  }

  get password(): FormControl {
    return this.formGroup.get('password') as FormControl;
  }

  constructor(
    private formBuilder: FormBuilder,
    private authService: AuthService,
    private router: Router
  ) {
  }

  ngOnInit(): void {
  }

  // 이메일과 비밀번호를 이용한 로그인
  loginWithEmailAndPassword(): void {
    this.authService.loginWithEmailAndPassword(
      this.email.value,
      this.password.value
    )
      .then((user) => {
        // 로그인 성공 시 HomeComponent로 이동
		goHome();
      })
      .catch(err => {
        // 로그인 실패 시
        console.error(err);
        alert(err.message);
      });
  }

  // 구글을 이용한 로그인
  loginWithGoogle(): void {
    this.authService.loginWithGoogle()
      .then((user) => {
        // 로그인 성공 시
        goHome();
      });
      .catch(err => {
        // 로그인 실패 시
        console.error(err);
        alert(err.message);
      });
  }
  
  goHome(): void {
    // HomeComponent로 이동
	this.router.navigate(['home']);
  }

}

그리고 login.component.html을 작성해줍니다.

로그인 버튼의 경우 email과 password가 유효한지에 따라 활성화 비활성화가 됩니다.

유효 여부는 LoginComponent FormGroup에 있는 Validators를 설정한 값으로 검사합니다.

<!-- login.component.html -->
<form 
  [formGroup]="formGroup"
  (ngSubmit)="loginWithEmailAndPassword()"
>
  <h1>로그인</h1>
  <div>
    <input
      type="email"
      placeholder="로그인을 위한 이메일을 입력해주세요"
      formControlName="email"
    />
  </div>
  <div>
    <input
      type="password"
      placeholder="로그인을 위한 비밀번호를 입력해주세요"
      formControlName="password"
    />
  </div>
  <div>
    <button
      type="submit"
      [disabled]="formGroup.invalid"
    >
      로그인
    </button>
  </div>
  <div>
    <button
      (click)="loginWithGoogle()"
      type="button"
    >
      구글로 로그인
    </button>
  </div>
  <div>
    <a
      routerLink="/sign-up"
    >
      회원가입
    </a>
  </div>
</form>

 

그 다음으로 회원가입입니다.

먼거 SignUpComponent를 작성하겠습니다.

LoginComponent와 거의 동일하지만 signUpWithEmailAndPassword를 사용합니다.

// sign-up.component.html
import {Component, OnInit} from '@angular/core';
import {FormBuilder, FormControl, Validators} from '@angular/forms';
import {AuthService} from '../services/auth.service';
import {Router} from '@angular/router';

@Component({
  selector: 'app-sign-up',
  templateUrl: './sign-up.component.html',
  styleUrls: ['./sign-up.component.sass']
})
export class SignUpComponent implements OnInit {
  formGroup = this.formBuilder.group({
    email: this.formBuilder.control('', [
      Validators.email,
      Validators.required
    ]),
    password: this.formBuilder.control('', [
      Validators.required,
      Validators.minLength(6)
    ])
  });

  get email(): FormControl {
    return this.formGroup.get('email') as FormControl;
  }

  get password(): FormControl {
    return this.formGroup.get('password') as FormControl;
  }

  constructor(
    private formBuilder: FormBuilder,
    private router: Router,
    private authService: AuthService
  ) {
  }

  ngOnInit(): void {
  }

  signUpWithEmailAndPassword(): void {
    this.authService.signUpWithEmailAndPassword(
      this.email.value,
      this.password.value
    )
    .then(() => {
      this.router.navigate(['home']);
    })
    .catch(err => {
      console.error(err);
      alert(err.message);
    });
  }

}

 

sign-up.component.html도 작성해주겠습니다.

로그인과 거의 동일합니다. 이메일과 비밀번호가 유효한지에 따라 회원가입 버튼이 활성화/비활성화됩니다. 그리고 로그인을 클릭할 시 로그인 페이지로 이동을 합니다.

<!-- sign-up.component.html -->
<form 
  [formGroup]="formGroup"
  (ngSubmit)="signUpWithEmailAndPassword()"
>
  <h1>회원가입</h1>
  <div>
    <input
      type="email"
      placeholder="회원가입을 위한 이메일을 입력해주세요"
      formControlName="email"
    />
  </div>
  <div>
    <input
      type="password"
      placeholder="회원가입을 위한 비밀번호를 입력해주세요"
      formControlName="password"
    />
  </div>
  <div>
    <button
      type="submit"
      [disabled]="formGroup.invalid"
    >
      회원가입
    </button>
  </div>
  <div>
    <a
      routerLink="/"
    >
      로그인
    </a>
  </div>
</form>

 

마지막으로 HomeComponent에서는 간단하게 로그인한 사용자의 displayName을 보여주도록 하겠습니다.

// home.component.ts
import {Component, OnInit} from '@angular/core';
import {AngularFireAuth} from '@angular/fire/auth';

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.sass']
})
export class HomeComponent implements OnInit {

  constructor(
    public afAuth: AngularFireAuth
  ) {
  }

  ngOnInit(): void {
  }

}
<!-- home.component.html -->
<h1>Hello, {{(afAuth.authState | async).displayName}}!!</h1>

아래 GIF에서 이메일, 비밀번호로 로그인 이후에 displayName이 나오지 않는건 따로 설정을 해주지 않아서 나오지 않습니다. 구글의 경우에는 구글에서 설정이 되어 있는 displayName을 받아와서 보여주기 때문에 나옵니다. 다음에 displayName 설정까지 알아보도록 하겠습니다.

 

728x90
반응형