본문 바로가기

Project/FirebaseTest

FireBase - 유효성 검사 + 사용자 등록

Validator

import Foundation

class Validator {
    
    static func isValidEmail(for email: String) -> Bool {
        let email = email.trimmingCharacters(in: .whitespacesAndNewlines)
        let emailRegEx = "[A-Z0-9a-z]+([._%+-]{1}[A-Z0-9a-z]+)*@[A-Z0-9a-z]+([.-]{1}[A-Z0-9a-z]+)*(\\.[A-Za-z]{2,4}){0,1}"
        let emailPred = NSPredicate(format: "SELF MATCHES %@", emailRegEx)
        return emailPred.evaluate(with: email)
    }
    
    static func isValidUsername(for username: String) -> Bool {
        let username = username.trimmingCharacters(in: .whitespacesAndNewlines)
        let usernameRegEx = "[A-Za-z0-9!@#$%^&*()._-]{5,16}"
        let userPred = NSPredicate(format: "SELF MATCHES %@", usernameRegEx)
        return userPred.evaluate(with: username)
    }
    
    static func isValidPassword(for password: String) -> Bool {
        let password = password.trimmingCharacters(in: .whitespacesAndNewlines)
        let passwordRegEx = "^(?=.*[A-Z])(?=.*[!@#$%^&*()_+=<>?]).{6,}$"
        let passwordPred = NSPredicate(format: "SELF MATCHES %@", passwordRegEx)
        return passwordPred.evaluate(with: password)
    }
    
}

 

위 코드는 Validator라는 이름의 유효성 검사 클래스를 정의하고, 이메일, 사용자 이름, 비밀번호의 유효성을 검사하는 메서드를 제공합니다. 각 메서드는 정규식(Regular Expression)과 NSPredicate를 사용하여 입력값이 특정 조건을 만족하는지 확인합니다.

 

코드 구성 및 설명

1. 클래스 선언

class Validator {
    static func ...
}
  • Validator:
    • 유효성 검사를 위한 유틸리티 클래스.
    • 모든 메서드는 static으로 선언되어, 인스턴스화 없이 클래스 이름으로 호출 가능.

 

2. 이메일 유효성 검사

static func isValidEmail(for email: String) -> Bool {
    let email = email.trimmingCharacters(in: .whitespacesAndNewlines)
    let emailRegEx = "[A-Z0-9a-z]+([._%+-]{1}[A-Z0-9a-z]+)*@[A-Z0-9a-z]+([.-]{1}[A-Z0-9a-z]+)*(\\.[A-Za-z]{2,4}){0,1}"
    let emailPred = NSPredicate(format: "SELF MATCHES %@", emailRegEx)
    return emailPred.evaluate(with: email)
}

 

  • 입력값 전처리:
    • trimmingCharacters(in: .whitespacesAndNewlines): 이메일 앞뒤의 공백 및 줄바꿈 제거.
  • 정규식(emailRegEx):
    • 이메일이 아래 조건을 만족하는지 확인:
      1. 알파벳, 숫자, 점(.), 언더스코어(_), 퍼센트(%), 더하기(+), 하이픈(-) 등 허용.
      2. @ 이후 도메인 이름 포함.
      3. 도메인 이름은 하위 도메인을 포함 가능.
      4. 선택적으로 도메인 끝에 2~4자의 확장자(.com, .org 등)를 포함.
  • 정규식 적용:
    • NSPredicate를 사용하여 정규식과 입력값을 비교.
    • 결과: 유효하면 true, 유효하지 않으면 false.

 

3. 사용자 이름 유효성 검사

static func isValidUsername(for username: String) -> Bool {
    let username = username.trimmingCharacters(in: .whitespacesAndNewlines)
    let usernameRegEx = "[A-Za-z0-9!@#$%^&*()._-]{5,16}"
    let userPred = NSPredicate(format: "SELF MATCHES %@", usernameRegEx)
    return userPred.evaluate(with: username)
}

 

  • 입력값 전처리:
    • trimmingCharacters(in: .whitespacesAndNewlines): 사용자 이름 앞뒤의 공백 및 줄바꿈 제거.
  • 정규식(usernameRegEx):
    • 사용자 이름이 아래 조건을 만족하는지 확인:
      1. 알파벳 대소문자(A-Z, a-z), 숫자(0-9), 특수문자(!@#$%^&*()._-)만 포함 가능.
      2. 길이는 5자 이상, 16자 이하.
  • 정규식 적용:
    • NSPredicate를 사용하여 정규식과 입력값을 비교.
    • 결과: 유효하면 true, 유효하지 않으면 false.

 

4. 비밀번호 유효성 검사

static func isValidPassword(for password: String) -> Bool {
    let password = password.trimmingCharacters(in: .whitespacesAndNewlines)
    let passwordRegEx = "^(?=.*[A-Z])(?=.*[!@#$%^&*()_+=<>?]).{6,}$"
    let passwordPred = NSPredicate(format: "SELF MATCHES %@", passwordRegEx)
    return passwordPred.evaluate(with: password)
}

 

  • 입력값 전처리:
    • trimmingCharacters(in: .whitespacesAndNewlines): 비밀번호 앞뒤의 공백 및 줄바꿈 제거.
  • 정규식(passwordRegEx):
    • 비밀번호가 아래 조건을 만족하는지 확인:
      1. 대문자(A-Z)가 1개 이상 포함.
      2. 특수문자(!@#$%^&*()_+=<>?)가 1개 이상 포함.
      3. 길이는 최소 6자 이상.
  • 정규식 적용:
    • NSPredicate를 사용하여 정규식과 입력값을 비교.
    • 결과: 유효하면 true, 유효하지 않으면 false.

 

유효한 입력값과 예시

1. 이메일

  • 유효한 이메일:
    • example@example.com
    • user.name@domain.co
  • 유효하지 않은 이메일:
    • example.com (도메인 누락)
    • user@domain (도메인 확장자 누락)

 

2. 사용자 이름

  • 유효한 사용자 이름:
    • user123
    • John_Doe
    • user-name!
  • 유효하지 않은 사용자 이름:
    • usr (5자 미만)
    • thisusernameistoolong123 (16자 초과)
    • user* (*는 허용되지 않는 특수문자)

 

3. 비밀번호

  • 유효한 비밀번호:
    • Abc!123
    • P@ssw0rd
  • 유효하지 않은 비밀번호:
    • password (특수문자와 대문자가 없음)
    • 123456 (대문자와 특수문자가 없음)
    • Short1! (6자 이상 충족하지 않음)

 

RegisterController

@objc private func didTapSignUp() {
        let username = self.usernameField.text ?? ""
        let email = self.emailField.text ?? ""
        let password = self.passwordField.text ?? ""
        
        let registerUserRequest = RegisterUserRequest(username: username,
                                                      email: email,
                                                      password: password)
        
        // Check Username
        if !Validator.isValidUsername(for: registerUserRequest.username) {
            AlertManager.showInvalidUsernameAlert(on: self)
            return
        }
        
        // Check Email
        if !Validator.isValidEmail(for: registerUserRequest.email) {
            AlertManager.showInvalidEmailAlert(on: self)
            return
        }
        
        // Check Password
        if !Validator.isValidPassword(for: registerUserRequest.password) {
            AlertManager.showInvalidPasswordAlert(on: self)
            return
        }

        AutheService.shared.registerUser(with: registerUserRequest) { wasRegistered, error in
            
            if let error = error {
                AlertManager.showSignInErrorAlert(on: self, with: error)
                return
            }
            
            if wasRegistered {
                if let sceneDelegate = self.view.window?.windowScene?.delegate as? SceneDelegate {
                    sceneDelegate.checkAuthentication()
                }
            } else {
                
            }
        }
    }

 

 

이 메서드는 사용자의 입력(사용자 이름, 이메일, 비밀번호)을 받아 회원가입 과정을 처리하는 역할을 합니다. 각 단계에서 유효성 검사를 수행하고, Firebase와 연동해 사용자 등록 및 앱의 화면 전환을 관리합니다.

 

코드의 주요 흐름 및 설명

1. 입력 데이터 준비

let username = self.usernameField.text ?? ""
let email = self.emailField.text ?? ""
let password = self.passwordField.text ?? ""

let registerUserRequest = RegisterUserRequest(username: username,
                                              email: email,
                                              password: password)

 

  • 사용자가 입력한 데이터를 텍스트 필드에서 읽어옵니다.
  • ?? "": 텍스트 필드가 비어 있을 경우 기본값으로 빈 문자열을 설정합니다.
  • 입력 데이터를 RegisterUserRequest 객체로 묶어 전달합니다.

 

2. 입력 유효성 검사

if !Validator.isValidUsername(for: registerUserRequest.username) {
    AlertManager.showInvalidUsernameAlert(on: self)
    return
}

 

 

 

  • 유효성 검사:
    • Validator 클래스의 메서드를 사용하여 사용자 이름, 이메일, 비밀번호가 유효한지 확인합니다.
  • 유효하지 않을 경우:
    • AlertManager를 통해 적절한 경고 메시지를 표시.
    • return: 잘못된 입력이 발견되면 회원가입 과정을 중단합니다.

 

3. 사용자 등록 요청

AutheService.shared.registerUser(with: registerUserRequest) { wasRegistered, error in
    ...
}

 

 

 

  • Firebase와 연동:
    • AutheService의 registerUser 메서드를 호출해 Firebase에 사용자 등록 요청을 보냅니다.
  • 결과 처리:
    • error: Firebase로부터 오류가 반환되었는지 확인.
      • 에러가 있으면 경고를 표시하고 종료.
    • wasRegistered: 사용자 등록이 성공적으로 이루어졌는지 확인.

 

4. wasRegistered의 필요성

if wasRegistered {
    ...
} else {
    ...
}

 

 

wasRegistered는 왜 필요할까?

  • error로만 처리할 수 없는 경우:
    • Firebase 호출이 성공적으로 완료되더라도, 내부적으로 데이터베이스에 사용자 정보 저장이 실패하는 등 추가적인 실패 조건이 있을 수 있습니다.
    • 예를 들어, Firestore에 데이터를 저장하는 단계에서 에러가 발생하면 wasRegistered가 false가 됩니다.
    • 따라서, error뿐 아니라 wasRegistered를 통해 전체 작업의 성공 여부를 확인해야 합니다.

 

5. 성공 시 화면 전환

if wasRegistered {
    if let sceneDelegate = self.view.window?.windowScene?.delegate as? SceneDelegate {
        sceneDelegate.checkAuthentication()
    }
}

 

회원가입 성공:

  • 사용자가 성공적으로 등록되었으면, SceneDelegate의 checkAuthentication 메서드를 호출.
  • 이 메서드는 로그인 상태를 확인하고, 로그인된 상태로 앱 화면을 전환합니다(예: 홈 화면으로 이동).

 

코드 흐름 요약

  1. 사용자 입력 처리:
    • 텍스트 필드에서 입력값을 가져와 RegisterUserRequest 객체 생성.
  2. 입력값 유효성 검사:
    • 이름, 이메일, 비밀번호가 조건을 만족하지 않으면 중단.
  3. 사용자 등록 요청:
    • Firebase를 통해 사용자 등록을 처리.
  4. 결과 확인:
    • error와 wasRegistered를 사용해 성공 여부 확인.
  5. 회원가입 성공 시:
    • 로그인 상태로 처리하고 홈 화면으로 이동

 

 

wasRegistered와 error의 차이점

  • error:
    • Firebase 작업에서 발생한 시스템 수준의 오류(예: 네트워크 문제, 인증 실패 등).
    • Firebase SDK 자체에서 반환.
  • wasRegistered:
    • 등록 작업의 비즈니스 로직 수준에서의 성공 여부.
    • Firebase에 사용자를 성공적으로 등록한 후, 데이터베이스에 사용자 정보를 저장하는 등의 추가 작업이 성공했는지를 나타냄.