FIREBASE CRUD authentification

FIREBASE CRUD authentification

Etape 2 - Authentification

Créer une page de connexion :

  • Storyboard : embed in Navigation controller - on peut supprimer la navigation bar en se positionnant sur la racine Navigation Controller et dans inspecteur d'attributs, décocher "Shows Navigation Bar".

  • Ajouter textFields, segment, bouton. Remplacer viewController par nouveau fichier LogController. Créer les IBOutlets.

class LogController: ViewController {

    @IBOutlet weak var mailTF: UITextField!
    @IBOutlet weak var passWordTF: UITextField!
    @IBOutlet weak var surnameTF: UITextField!
    @IBOutlet weak var nameTF: UITextField!
    @IBOutlet weak var segmented: UISegmentedControl!

Création nouveau fichier FireAuth.swift et utilisation Auth.auth() pour vérifier l'authentification

import Firebase

class FireAuth {
    func isAuth() -> Bool {
        return Auth.auth().currentUser?.uid != nil
    }
}

Dans LogController.swift, implémentation des fonctions setupUI(), updateVisible(), pour afficher les textFields en fonction d'une connexion ou création de compte.

func setupUI() {
        if FireAuth().isAuth() { 
            print("auth == true")
        } else {
            updateVisible(true, mailTF)
            updateVisible(true, passWordTF)
            let bool = segmented.selectedSegmentIndex != 0 
            updateVisible(bool, surnameTF)
            updateVisible(bool, nameTF)
        }
    }
    func updateVisible(_ bool: Bool, _ view: UIView) {
        view.isHidden = !bool
    }

Ajout de "override func touchesBegan" pour cacher le clavier.

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        view.endEditing(true)
    }

Dans "func validateButton()" on gère les champs textFields. Si les champs sont vides on prévoit des alertes pour différents cas de figure (champs vide, erreur,....).

ALERTES :

Pour utiliser ces alertes dans toute l'application, on crée une fonction "Alerte" dans un controller racine = un RootController. Chaque alerte aura un titre et un message en fonction de la situation, d'où les paramètres de la fonction :

func showAlert(_ titre: String?, _ message: String?) {
        let alert = UIAlertController(title: titre, message: message, preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "retour", style: .destructive, handler: { (action) in
            alert.removeFromParent()
    }))
    self.present(alert, animated: true, completion: nil)

    }

On ajoute une action à l'alerte pour la fermer, dans une closure.

LogController hérite donc de RootController, pour utiliser les alertes

class LogController: RootController {

Les alertes sont gérables, on implémente les différents cas de champs vides, dans la fonction "validateButton()"

@IBAction func validateButton(_ sender: UIButton) {
        if let mail = mailTF.text, mail != "" {
            if let password = passWordTF.text, password != "" {
                if segmented.selectedSegmentIndex == 0 {
                    //Authentification

                } else {
                    if let surname = surnameTF.text, surname != "" {
                        if let name = nameTF.text, name != "" {

                        } else {
                            //Alert pas de name
                            showAlert("Champs vide", "Merci de renseigner votre nom")
                        }
                    } else {
                        //Alert pas de surname
                        showAlert("Champs vide", "Merci de renseigner votre prénom")
                    }
                }
            } else {
                //alert pas de pwd
                showAlert("Champs vide", "Merci de renseigner votre mot de passe")
            }
        } else {
            // alert pas de mail
            showAlert("Champs vide", "Merci de renseigner votre adresse mail")
        }
    }

Authentification

Dans Firebase/Authentification, choisir l'authentification par email et mot de passe.

Le Auth de Firebase va géré l'email et le mot de passe, donc peut indiquer si on est connecté ou pas.

Les informations sur l'utilisateur (nom, prénom) vont être stockées dans une base de données à part = CloudFirestore.

Donc dans Firebase/CloudFirestore, créer une base de données, en mode de production. Choisir la zone géographique de stockage.

Dans les règles de sécurité (rules), autoriser la lecture et l'écriture si on est identifié, à la place de "if false"

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if request.auth != null;
    }
  }
}

Retour dans Xcode

Dans FireAuth.swift, implémenter les fonctions signIn(), createUser(), et signOut()

var completion: ((_ uid: String?, _ error: String?) -> Void)?

func signIn(_ mail: String, _ pwd: String, completion: ((_ uid: String?, _ error: String?) -> Void)?) {
        self.completion = completion
        Auth.auth().signIn(withEmail: mail, password: pwd, completion: handleResult(_:_:))
    }

    func createUser(_ mail: String, _ pwd: String, completion: ((_ uid: String?, _ error: String?) -> Void)?) {
        self.completion = completion
        Auth.auth().createUser(withEmail: mail, password: pwd, completion: handleResult(_:_:))
    }

    func signOut() { 
    }

    func handleResult( _ data: AuthDataResult?, _ error: Error?) {
        if error != nil {
            self.completion?(nil, error?.localizedDescription)
        }
        if let uid = data?.user.uid {
            self.completion?(uid, nil)
        }
    }

On créé un nouveau fichier pour la base de données CloudFirestore = FireDatabase.swift

Et on implémente la "func addUser()"

import Firebase

class FireDatabase {

    // chemin d'accès à la base du projet
    let base = Firestore.firestore()

    // chemin d'accès à la collection nommée "users", si elle n'existe pas, elle est créée
    var usersCollection: CollectionReference {
        return base.collection("users")
    }

    func addUser(_ uid: String, data: [String: Any]) {
        usersCollection.document(uid).setData(data)
        // dans la collection "users", on créé un document attaché à l'uid de Auth
        // ce document comprendra un tableau de data, exemple : [name: wood, surname: matt]
    }
}

Dans LogController.swift, on se sert des nouvelles fonctions dans "func validateButton()"

@IBAction func validateButton(_ sender: UIButton) {
        if let mail = mailTF.text, mail != "" {
            if let password = passWordTF.text, password != "" {
                if segmented.selectedSegmentIndex == 0 {
                    //Authentification
                    FireAuth().signIn(mail, password) { (uid, error) in
                        if error != nil {
                            self.showAlert("Erreur", "erreur lors lors de l'authentification")
                        }
                        if uid != nil {
                            //vers le controller suivant
                        }
                    }

                } else {
                    if let surname = surnameTF.text, surname != "" {
                        if let name = nameTF.text, name != "" {
                            //Création du compte
                            FireAuth().createUser(mail, password) { (uid, error) in
                                if error != nil {
                                    self.showAlert("Erreur", "erreur lors de la création du compte")
                                }
                                if uid != nil {
                                    let data: [String: Any] = ["name": name, "surname": surname, "uid": uid!]
                                    FireDatabase().addUser(uid!, data: data)

                               // affichage alerte pour confirmer la connexion, à supprimer par la suite
                                    self.showAlert("Bienvenue \(surname)", "votre compte a été créé")
                                }
                            }

                        } else { ...