Firebase Authentication の iOS 導入手順【③メールアドレス・パスワード認証によるログイン・ログアウト編】【SwiftUI】

前回②ユーザー登録編の続きです。

今回はログイン・ログアウトについて実装方法について紹介します。

他の Firebase Authentication についての記事一覧は以下の通りです。

Firebase Authentication の iOS 導入手順【③メールアドレス・パスワード認証によるログイン・ログアウト編】【SwiftUI】

(1) ログイン中ユーザー情報を取得する

ログインやログアウトを行う前に、先ずログインしているユーザー情報を取得する方法について確認します

ログインしているユーザー情報を取得するには、

Auth.auth().currentUser()

を使用します。

if let user = Auth.auth().currentUser {
    ログインしている
} else {
    ログインしていない
}

この判定でログインフォームやログアウトボタンの出し分けなどを行うと良いでしょう。

(2) ログインする

メールアドレスとパスワードによるログインをするには、

Auth.auth().signIn(withEmail: email, password: password)

を使用します。

Auth.auth().signIn(withEmail: self.mailAddress, password: self.password) { authResult, error in
    if authResult?.user != nil {
        ログイン成功
    } else {
        ログイン失敗
    }
}

ログインが成功すると、ユーザー登録(createUser)時と同じく、返り値の authResult からユーザー情報を確認することが出来ます

(3) ログアウトする

ログアウトするには、

Auth.auth().signOut()

を使用します。

返り値はない為、公式ガイドにもあるように、通常は例外発生を見越して do〜try〜catch の形式を取ります

do {
    try Auth.auth().signOut()
} catch let signOutError as NSError {
    print("SignOut Error: %@", signOutError)
}

(4) ログイン・ログアウトの実装例

最後に、簡易的な SwiftUI のフォームを用いて、メールアドレス・パスワード認証によるログイン・ログアウトの実装例を紹介します(前回のユーザー登録の例と同じくエラー対応などは最小限としていますのでご了承ください)。

import SwiftUI
import FirebaseAuth

struct AuthTestSignInView: View {
    
    @State private var isSignedIn = false
    
    @State private var mailAddress = ""
    @State private var password = ""
    
    @State private var isShowAlert = false
    @State private var isError = false
    @State private var errorMessage = ""
    
    @State private var isShowSignedOut = false
    
    var body: some View {
        HStack {
            Spacer().frame(width: 50)
            VStack(spacing: 16) {
                if self.isSignedIn {
                    Text("ログインしています").foregroundColor(.green)
                } else {
                    Text("ログインしていません").foregroundColor(.gray)
                }
                TextField("メールアドレス", text: $mailAddress).textFieldStyle(RoundedBorderTextFieldStyle())
                SecureField("パスワード", text: $password).textFieldStyle(RoundedBorderTextFieldStyle())
                Button(action: {
                    self.errorMessage = ""
                    if self.mailAddress.isEmpty {
                        self.errorMessage = "メールアドレスが入力されていません"
                        self.isError = true
                        self.isShowAlert = true
                    } else if self.password.isEmpty {
                        self.errorMessage = "パスワードが入力されていません"
                        self.isError = true
                        self.isShowAlert = true
                    } else {
                        self.signIn()
                    }
                }) {
                    Text("ログイン")
                }
                .alert(isPresented: $isShowAlert) {
                    if self.isError {
                        return Alert(title: Text(""), message: Text(self.errorMessage), dismissButton: .destructive(Text("OK"))
                        )
                    } else {
                        return Alert(title: Text(""), message: Text("ログインしました"), dismissButton: .default(Text("OK")))
                    }
                }
                Button(action: {
                    self.signOut()
                }) {
                    Text("ログアウト")
                }
                .alert(isPresented: $isShowSignedOut) {
                    Alert(title: Text(""), message: Text("ログアウトしました"), dismissButton: .default(Text("OK")))
                }
            }
            Spacer().frame(width: 50)
        }
        .onAppear() {
            self.getCurrentUser()
        }
    }
    
    private func getCurrentUser() {
        if let _ = Auth.auth().currentUser {
            self.isSignedIn = true
        } else {
            self.isSignedIn = false
        }
    }
    
    private func signIn() {
        Auth.auth().signIn(withEmail: self.mailAddress, password: self.password) { authResult, error in
            if authResult?.user != nil {
                self.isSignedIn = true
                self.isShowAlert = true
                self.isError = false
            } else {
                self.isSignedIn = false
                self.isShowAlert = true
                self.isError = true
                if let error = error as NSError?, let errorCode = AuthErrorCode(rawValue: error.code) {
                    switch errorCode {
                    case .invalidEmail:
                        self.errorMessage = "メールアドレスの形式が正しくありません"
                    case .userNotFound, .wrongPassword:
                        self.errorMessage = "メールアドレス、またはパスワードが間違っています"
                    case .userDisabled:
                        self.errorMessage = "このユーザーアカウントは無効化されています"
                    default:
                        self.errorMessage = error.domain
                    }
                    
                    self.isError = true
                    self.isShowAlert = true
                }
            }
        }
    }
    
    private func signOut() {
        do {
            try Auth.auth().signOut()
            self.isShowSignedOut = true
            self.isSignedIn = false
        } catch let signOutError as NSError {
            print("SignOut Error: %@", signOutError)
        }
    }
}

以上、次回④メールアドレスとパスワードの更新編に続きます。