[UIKit] Firebase Chat App: Naver Sign In & Sign Out

Junyoung Park·2022년 9월 18일
0

UIKit

목록 보기
37/142
post-thumbnail
post-custom-banner

Naver Sign In iOS

Firebase Chat App: Naver Sign In & Sign Out

구현 목표

  • 네이버 간편 로그인 구현

구현 태스크

  1. 네이버 API 사용 관련 개발자 등록 및 URL 작성
  2. SceneDelegate 등 URL 패치 함수 구현
  3. 네이버 로그인 버튼 UI
  4. 네이버 로그인 완료 여부 확인
  5. 로그인 이후 사용자 정보 패치 HTTP GET 사용
  6. 파이어베이스 이메일/패스워드 기반 인증 연동

핵심 코드

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        ...
        let instance = NaverThirdPartyLoginConnection.getSharedInstance()
        instance?.isNaverAppOauthEnable = true
        instance?.isInAppOauthEnable = true
        instance?.serviceUrlScheme = kServiceAppUrlScheme
        instance?.consumerKey = kConsumerKey
        instance?.consumerSecret = kConsumerSecret
        instance?.appName = kServiceAppName
        return true
    }
    func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
        ...  NaverThirdPartyLoginConnection.getSharedInstance()?.application(app, open: url, options: options)
       ...
    func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
        if let url = URLContexts.first?.url {
        ...
        NaverThirdPartyLoginConnection.getSharedInstance()?.receiveAccessToken(url)
        }
    }
private let naverLoginInstance = NaverThirdPartyLoginConnection.getSharedInstance()
...
naverLoginInstance?.delegate = self
...
naverLoginInstance?.requestThirdPartyLogin()
  • 네이버 로그인 버튼 클릭 시 해당 싱글턴 인스턴스의 로그인 함수 작동 (버튼에 함수 추가 필요)
extension SignInViewController: NaverThirdPartyLoginConnectionDelegate {
    private func getUserFromNaver() {
        guard
            let isValidAccessToken = naverLoginInstance?.isValidAccessTokenExpireTimeNow(),
            isValidAccessToken == true,
            let tokenType = naverLoginInstance?.tokenType,
            let accessToken = naverLoginInstance?.accessToken,
            let url = URL(string: "https://openapi.naver.com/v1/nid/me")
        else {
            return
        }
        var urlRequest = URLRequest(url: url)
        let authorization = tokenType + " " + accessToken
        urlRequest.httpMethod = "GET"
        urlRequest.addValue(authorization, forHTTPHeaderField: "Authorization")
        URLSession.shared.dataTask(with: urlRequest) { data, response, error in
            guard
                let data = data,
                let response = response,
                error == nil else {
                if let error = error {
                    print(error.localizedDescription)
                }
                return
            }
            do {
                let result = try JSONDecoder().decode(NaverProfileModel.self, from: data)
                let firstName = result.response.name
                let lastName = result.response.nickname ?? ""
                let email = result.response.email
                let password = result.response.id
                self.thirdPartyToFirebaseAuth(firstName: firstName, lastName: lastName, email: email, password: password, platform: .Naver)
            } catch {
                print(error.localizedDescription)
            }
        }
        .resume()
    }
    
    func oauth20ConnectionDidFinishRequestACTokenWithAuthCode() {
        print("Successfully Naver Sign In")
        getUserFromNaver()
    }
    
    func oauth20ConnectionDidFinishRequestACTokenWithRefreshToken() {
        print(naverLoginInstance?.accessToken)
        getUserFromNaver()
    }
    
    func oauth20ConnectionDidFinishDeleteToken() {
        print("Naver Token Deleted")
    }
    
    func oauth20Connection(_ oauthConnection: NaverThirdPartyLoginConnection!, didFailWithError error: Error!) {
        print("DID FAIL")
        print(error.localizedDescription)
    }
}
  • 네이버 로그인 유효 토큰 사용
  • 로그인 확인 이후 액세스 토큰 이용 프로필 조회 API 사용
  • 리턴받은 데이터로 파이어베이스 실시간 데이터베이스 조회
  • 파이어베이스 이메일/패스워드 기반 인증에 적용하기
import Foundation

struct NaverProfileModel: Codable {
    let resultcode: String
    let message: String
    let response: ResponseModel
}

struct ResponseModel: Codable {
    let id: String
    let name: String
    let email: String
    let nickname: String?
}
  • 프로필에 필요한 이메일, 이름 정보만 요청(어플리케이션 API 사용에 필요)
    private func thirdPartyToFirebaseAuth(firstName: String, lastName: String, email: String, password: String, platform: Platform) {
        DatabaseManager.shared.userExists(with: email, at: platform) { exists in
            if !exists {
                print("THERE IS NO FIREBASE \(platform.rawValue) USER")
                DatabaseManager.shared.insertUser(with: ChatAppUser(firstName: firstName, lastName: lastName, emailAddress: email, platform: platform))
                FirebaseAuth.Auth.auth().createUser(withEmail: platform.rawValue.lowercased() + email, password: password) { result, error in
                    guard
                        let _ = result,
                        error == nil else {
                        if let error = error {
                            print(error.localizedDescription)
                        }
                        return
                    }
                    self.thirdPartyToSignIn(email: email, password: password, platform: platform)
                }
            } else {
                print("THIS EMAIL EXISTS")
                self.thirdPartyToSignIn(email: email, password: password, platform: platform)
            }
        }
    }
    
    private func thirdPartyToSignIn(email: String, password: String, platform: Platform) {
        FirebaseAuth.Auth.auth().signIn(withEmail: platform.rawValue.lowercased() + email, password: password) { [weak self] result, error in
            guard let self = self else { return }
            guard
                let _ = result,
                error == nil else {
                if let error = error {
                    print(error.localizedDescription)
                }
                return
            }
            print("Successfully \(platform.rawValue) Sign In")
            NotificationCenter.default.post(name: .didSignInNotification, object: nil)
        }
    }
  • 카카오톡 기반 데이터를 파이어베이스 인증에 사용한 함수를 리팩토링
  • 이메일, 패스워드, 플랫폼 정보를 통해 파이어베이스 데이터정보 사용자 존재 파악 및 유저 생성 또는 로그인

구현 화면

profile
JUST DO IT
post-custom-banner

0개의 댓글