Firebase Authentication

  1. Firebase 사이트에서 프로젝트를 만들고,
  2. 해당 프로젝트에서 iOS 앱을 만들고
  3. GoogleService-Info.plist 파일을 추가
  4. 그리고 Firestore configure 코드(초기화 코드)까지 추가한 상태이다.

서버 백엔드를 따로 구축한다고 해도, Firebase Authentication은 따로 쓰는 것도 괜찮다. 왜냐하면 Firebase Authentication은 따로 만드는 것보다 더 간편하고 효율적이기 때문이다.

Firebase auth 에서 볼 수 있듯이 인증 한도도 일일 활성사용자량 3000명 정도로, 초기 앱에 사용하기에는 괜찮은 편이다.

사용자의 인증 상태를 관리하는 AuthViewModel 코드를 살펴보자.

import SwiftUI
import FirebaseAuth

final class AuthViewModel: ObservableObject {
    @Published var user: User?
    
    func listenToAuthState() {
        Auth.auth().addStateDidChangeListener { [weak self] _, user in
            self?.user = user
        }
    }
}

listenToAuthState 라는 함수를 호출 시 addStateDidChangeListener 를 통해 파이어베이스 서버로부터 인증 상태를 계속 관리할 수 있다.

사용자의 인증 상태가 변경될 때마다 호출되므로 즉 파이어베이스에서 로그인 / 로그아웃 시, 인증 상태가 변경되므로 addStateDidChangeListener가 호출된다.

그리고 해당 user가 있는지 없는 지에 따라 로그인 뷰나 컨텐츠뷰로 리디렉션하는 HolderView 를 구성하는 것부터 시작이다.

로저 내부에서 self를 약하게 캡처하여 메모리 누수를 방지한다. 이는 AuthViewModel 객체가 더 이상 필요하지 않을 때 메모리에서 해제될 수 있도록 한 것이다.

struct HolderView: View {
    @EnvironmentObject var authViewModel: AuthViewModel
    
    var body: some View {
        Group {
            if authViewModel.user == nil {
                SignUpView()
            } else {
                ContentView()
            }
        }
        .onAppear {
            authViewModel.listenToAuthState()
        }
    }
}

그리고 로그인, 로그아웃 그리고 회원가입을 위한 function 을. 만든다. 이것도 마찬가지로 Firebase Auth 에 이미 정의되어 있는 함수를 사용하기만 하면 된다..

    func signIn(emailAddress: String, password: String) {
        Auth.auth().signIn(withEmail: emailAddress, password: password) { result, error in
            if let error = error {
                print("Error: \(error.localizedDescription)")
                return
            }
        }
    }
    
    func signUp(emailAddress: String, password: String) {
        Auth.auth().createUser(withEmail: emailAddress, password: password) { result, error in
            if let error = error {
                print("Create Error: \(error.localizedDescription)")
                return
            }
            dump(result)
        }
    }
    
    func signOut() {
        do {
            try Auth.auth().signOut()
        } catch let signOutError as NSError {
            print("Sign Out Error: \(signOutError.localizedDescription)")
        }
    }

인증된 사용자의 컨텐츠만 보이도록 하기

이번에는 Firebase Auth 와 Firebase firestore 를 함께 사용해볼 것이다.

그리고 인증된 사용자가 생성한 콘텐츠, 예를 들어 Note 라는 콘텐츠를 특정 사용자가 만든 것만 보이게 할 것이다.

그러면, 해당 note 컬렉션을 그냥 만드는 것이 아니라, User 모델 안에 note 컬렉션을 만들 수 있다.

image

이게 아니라,

아래와 같이 User 안에 userId 안에서 Note를 만들겠다는 것.

image2

코드로는


//    private var databaseReference = Firestore.firestore().collection("Notes")
    
    private lazy var databaseReference: CollectionReference? = {
         guard let userId = Auth.auth().currentUser?.uid else { return nil }
         let ref = Firestore.firestore().collection("Users").document(userId).collection("Posts")
         return ref
    }()

이렇게 될 것이다.

Security roles

그리고 반드시 인증한 유저만 해당 uid의 document 만 볼 수 있도록, Firestore 규칙을 설정해줘야 한다.

service cloud.firestore {
  match /databases/{database}/documents {

    // your rules
    match /{document=**} {
      allow read, write: false;
    }
    match /Users/{uid}/{document=**} {
      allow read, write: if uid == request.auth.uid;
    }
  }
}

서버에