본문 바로가기
iOS/개발

Swift SupaBase Auth 비밀번호 초기화 + 변경

by 바등쪼 2023. 3. 28.

지난번 SupaBase Storage에 이미지 업로드하기에 이어 이번에는 SupaBase를 사용하여 비밀번호 초기화 + 변경 기능을 구현해보자!

비밀번호를 잊었을 때 일반적으로 비밀번호 찾기 버튼을 누르면 메일을 발송 + 메일을 클릭해 본인 인증을 하면 기존의 비밀번호가 초기화 되고 새 비밀번호를 설정하는 로직

1. 비밀번호 찾기/초기화 뷰 구현

  • 로그인 화면에 비밀번호 찾기/리셋 버튼을 넣는다.
  • 해당 버튼을 클릭하면 비밀번호를 변경할 이메일을 입력 받는 뷰로 이동시킨다.

  • 이메일을 입력 받으면 SupaBase sdk를 불러와서 해당 이메일로 PasswordReset 메일을 발송한다.

2. 딥링크 설정

  • 뷰 구현을 하고 SupaBase 코드를 사용하기 전에 우선 SupaBase 홈페이지에서 URL 설정 + 프로젝트에서 딥링크 Scheme 을 설정해야한다.
  • Project - Targets - Info - URL Types에 + 버튼을 눌러 URL Scheme을 설정한다

  • SupaBase 홈페이지에 가서 해당되는 프로젝트 클릭 - Authentication - URL Configuration - Site URL에 앞서 적은 URL Schemes + host를 적는다. 예를 들어, example://reset 이런식으로!
  • 이제 사용자가 받은 메일에 있는 링크를 클릭하면 우리가 설정한 딥링크로 인해 앱이 실행된다.

3. 이메일 발송 코드 구현

func resetPasswordForEmail(email: String) async -> Result<Void, MyError> {
    do {
      try await SupaClient.shared.auth.resetPasswordForEmail(email, redirectTo: URL(string: "example://reset")!)

      return .success(())
    } catch {
      return .failure(.supabaseResetPasswordFailed(error: error))
    }
}
  • 사용자가 이메일을 입력하고 인증하기 버튼을 클릭하면 이 함수가 실행되어 본인 인증을 할 수 있는 메일이 발송되도록 한다.
  • redirectTo에 앞서 정한 Site URL을 넣는다.

이런 이메일이 오고 아래의 Reset Password를 누르면 앱이 실행된다!

 

4. 비밀번호 변경 뷰로 연결

  • 위와 같은 비빌번호를 새롭게 변경할 수 있도록 하는 뷰를 구현한다.
  • 앞서 사용자가 받은 이메일의 링크를 클릭하면 우리가 만든 앱이 실행되고 진입하는 화면이 지금 만든 비밀번호 변경 뷰가 되도록 해야한다.
  • UIKit을 사용하는 경우에는 AppDelegate.swift에서 해당 처리를 한다
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
    if url.host == "reset" {
    	// 비밀번호 찾기 뷰로 이동
    }
    return true
}
  • 현재 진행중인 프로젝트는 SwiftUI 기반이기 때문에 ContentView에 onOpenURL 를 지정하여 딥링크로 열었을 때를 핸들링한다.
var body: some View {
    ZStack {
    	// 생략
    }
    .onOpenURL { url in
      AsyncTask {
        await viewModel.updateSession(with: url)
      }
   }
}
  • 여기서 받은 url(SupBase가 발급해준)을 잘 살펴보면 url에 accessToken가 refreshToken이 담겨 있는 것을 확인할 수 있다.
  • 이것을 이용해 새로운 Session을 생성하고 사용자를 임시 로그인을 시킨 후 비밀번호를 재설정 + SupBase에 변경한 비밀번호로 사용자 정보 update를 진행한다.
  • 이 부분에서 시간이 꽤 걸렸는데, 왜냐하면 이메일에서 링크를 클릭하여 앱이 받은 URL에 token들이 있는줄 몰랐기 때문이다.. 사용자 정보(비밀번호)를 업데이트 하려면 로그인이 되어 있어야하는데 이를 위해 세션이 필요하다. 사용자가 현재 비밀번호를 몰라서 로그인을 못하고 있는 상황인데 이 세션을 어떻게 만들지.. 이런 고민을 하다가 삽질 끝에 URL에 토큰이 담겨 오는 것을 발견했다..!!!
  • 이 토큰들로 세션을 생성하고 비밀번호 업데이트를 진행하면 된다.
func updateSession(with url: URL) async -> Result<Session, MyError> {
    guard let session = try? await SupaClient.shared.auth.session(from: url) else {
      return .failure(.supabaseNoSession)
    }
    do {
      let session = try await SupaClient.shared.auth.setSession(accessToken: session.accessToken, refreshToken: session.refreshToken)
      return .success(session)
    } catch {
      return .failure(.supabaseUpdateSessionFailed(error: error))
    }
}

5. 비밀번호 업데이트

  • 비밀 번호 변경 뷰에서 비밀번호 변경 버튼을 클릭하면 사용자가 새로 지정한 비밀번호로 DB 정보를 업데이트한다.
func updatePassword(password: String) async -> Result<GoTrue.User, MyError> {
    do {
      let user = try await SupaClient.shared.auth.update(user: UserAttributes(password: password))
      await signOut()
      return .success(user)
    } catch {
      return .failure(.supabaseResetPasswordFailed(error: error))
    }
}
  • 비밀번호를 성공적으로 업데이트하면 사용자를 다시 로그인 뷰로 보내기 위해 SignOut()을 진행한다.
func signOut() async -> Result<String, MyError> {
    do {
      try await SupaClient.shared.auth.signOut()
      return .success("로그아웃 성공")
    } catch {
      return .failure(.supabaseSignOutFailed(message: "로그아웃 try 실패함"))
    }
}

 

정리

우리의 목표는 사용자가 비빌번호를 까먹어 로그인을 못할 때를 위해 비밀번호를 재설정할 수 있도록 기능을 제공하는 것이었다.

구현의 흐름을 요약하면 다음과 같다!

  1. 필요한 뷰들 구현 (이메일 입력, 새 비밀번호 입력 뷰)
  2. Targets info에 딥링크를 위한 설정
  3. SupaBase 홈페이지 URL Configuration 설정
  4. 이메일을 입력받으면 resetPasswordForEmail 실행
  5. 딥링크로 앱이 실행되면 이를 체크(ContentView에서 onOpenURL에서)하여 비밀번호 변경 뷰로 이동시키기
  6. 5에서 받은 url로 임시 Session 생성
  7. 사용자가 새로 입력한 비밀번호로 유저 정보를 update 하기 (임시 세션 상태에서)
  8. 성공하면 사용자를 다시 SignOut 시키고 로그인 뷰로 이동시키기
  9. 새로 만든 비밀번호로 로그인

댓글