[iOS] 네이버 아이디로 로그인 구현하기 with SwiftUI

parkgyurim·2022년 2월 6일
4

iOS

목록 보기
1/5
post-thumbnail

💻 이 글은 Swift 5.0, Xcode Version 13.2.1 를 바탕으로 작성하였습니다.

Naver ID Login SDK for iOS

네이버 로그인 SDK는 서드파티 애플리케이션에서 네이버 계정, 애플리케이션으로 로그인, 로그아웃, 토큰 관리, 연동 해제 등의 기능을 쉽게 구현할 수 있게 합니다.

인증 절차

네이버 아이디로 로그인은 OAuth2.0 프로토콜을 기반으로 사용자 인증 기능을 제공합니다.

OAuth2.0

1. Authorization Code 얻기
네이버 앱 또는 브라우져에서 간편 로그인 프로세스 (Authentication) 를 거쳐 Authorization Code 를 얻고, URL Scheme 으로 등록된 자신의 앱으로 코드가 포함된 URL 을 가지고 리다이렉트 됩니다. 그리고 앱에서 이 URL이 네이버 로그인을 위한 URL인지 판단합니다.

2. Authorization Code로 Token 얻기
네이버 로그인을 위한 URL이라고 판단이 되면, Authorization Code 로 네이버 서버에 Access Token 과 Refresh Token 을 요청합니다.

3. API 호출
발급받은 Access Token 을 헤더에 담아 다른 API를 요청할 수 있습니다.

요구사항

iOS 9.0 이상
XCode 9.0 이상

요구하는 환경의 버전이 상당히 낮은데, iOS용 네이버 로그인 SDK는 Objective-C...로 만들어졌습니다. 그리고 대다수의 자료들이 UIKit Lifecycle 기반이라서 구현에 조금 어려움을 겪었는데요, SwiftUI Lifecycle 로 구현하는 방법을 기술해보도록 하겠습니다.


설치방법

Cocoapods로 설치하기

프로젝트 폴더에서 Pod init → Podfile에 아래 코드를 추가 → Pod install

pod 'naveridlogin-sdk-ios'

프로젝트 설정

애플리케이션 등록

Naver Developers (https://developers.naver.com/main/) 의 [Application] 탭으로 이동해서 애플리케이션을 등록합니다. 사용할 네이버 오픈 API와 제공받을 정보를 선택하고, URL Scheme을 등록합니다. 이때 URL Scheme은 소문자로만 구성하는 것을 권장드립니다.

info.plist 설정

  • [Info] > [Custom iOS Target Properties]에 LSApplicationQueriesSchemes를 추가 (Array 타입)
  • 해당 키의 아이템으로 커스텀 URL 스킴에 사용할 값인 naversearchapp, naversearchthirdlogin을 추가

URL Schemes 설정

바로 아래의 URL Types을 펼쳐 아까 등록했던 URL Scheme을 추가합니다.

상수값 설정

프로젝트 폴더에서 [Pods > naveridlogin-sdk-ios > NaverThirdPartyLogin.framework 우클릭후 패키지 내용 보기 > Headeras > NaverThirdPartyConstantsForApp.h] 를 열어 제일 아래 define된 4개의 변수를 자신의 프로젝트에 맞게 수정해줍니다.

#define kServiceAppUrlScheme    @"[앱 등록때 설정한 URL Scheme]"
#define kConsumerKey            @"[애플리케이션 정보 > Client ID]"
#define kConsumerSecret         @"[애플리케이션 정보 > Client Secret]"
#define kServiceAppName         @"[앱 이름]"

초기화

프로젝트 최상위 코드인 [project name]App.swift 의 초기화 함수 init() 에서 NaverThirdPartyLogin 초기화 코드를 작성해줍니다.

import SwiftUI
import NaverThirdPartyLogin

@main
struct NanuriApp: App {
    init() {
        // Naver SDK Initializing
 
 		// 네이버 앱으로 로그인 허용
        NaverThirdPartyLoginConnection.getSharedInstance()?.isNaverAppOauthEnable = true 
        // 브라우저 로그인 허용
        NaverThirdPartyLoginConnection.getSharedInstance()?.isInAppOauthEnable = true 
 
        // 네이버 로그인 세로모드 고정
        NaverThirdPartyLoginConnection.getSharedInstance().setOnlyPortraitSupportInIphone(true)
        
        // NaverThirdPartyConstantsForApp.h에 선언한 상수 등록
        NaverThirdPartyLoginConnection.getSharedInstance().serviceUrlScheme = kServiceAppUrlScheme
        NaverThirdPartyLoginConnection.getSharedInstance().consumerKey = kConsumerKey
        NaverThirdPartyLoginConnection.getSharedInstance().consumerSecret = kConsumerSecret
        NaverThirdPartyLoginConnection.getSharedInstance().appName = kServiceAppName
    }
    
	var body : some View {
    	WindowGroup {
	    	ContentView()
            	.onOpenURL { url in 
            		if NaverThirdPartyLoginConnection
                    		.getSharedInstance()
                            .isNaverThirdPartyLoginAppschemeURL(url) 
                    {                            
	                	// Token 발급 요청
	    	            NaverThirdPartyLoginConnection
    	    	            .getSharedInstance()
        	    	        .receiveAccessToken(url)
            		}
        }
	}
}

네이버 로그인은 로그인을 위해 네이버 앱 또는 브라우저로 이동한 후, 사용자의 동의 이후에 다시 앱으로 이동하는 과정을 거칩니다. 이때 다시 앱으로 돌아왔을 때 네이버 로그인을 처리하기 위해 .onOpenURL { ... } 다음 코드를 추가해야 합니다. 리다이렉트되어 돌아올때 갖고 있는 URL 이 네이버 로그인을 위한 URL 인지 판단을 하고 맞다면 토큰을 요청하는 것 입니다.


Delegate 구현

네이버 로그인을 구현하기 위해서는 네이버 로그인이 실행되었을때 필요한 delegate가 필요한데 스유에서 구현하기 위해서 viewModel 을 extension 했습니다. 그리고 viewModel 은 NSObject와 UIApplicationDelegate 를 상속해야 합니다.

extension MyPageViewModel : UIApplicationDelegate, NaverThirdPartyLoginConnectionDelegate {
    // 토큰 발급 성공시
    func oauth20ConnectionDidFinishRequestACTokenWithAuthCode() { ... }
    // 토큰 갱신시 
    func oauth20ConnectionDidFinishRequestACTokenWithRefreshToken() { ... }
    // 로그아웃(토큰 삭제)시 
    func oauth20ConnectionDidFinishDeleteToken() { ... }
    // Error 발생
    func oauth20Connection(_ oauthConnection: NaverThirdPartyLoginConnection!, didFailWithError error: Error!) { ... }
}

네이버 로그인은 NaverThirdPartyLoginConnection의 싱글턴 객체인 .getSharedInstance() 를 통해서 모든 작업이 이루어집니다!

네이버 로그인 호출

Button {
	if NaverThirdPartyLoginConnection
		.getSharedInstance()
		.isPossibleToOpenNaverApp() // Naver App이 깔려있는지 확인하는 함수
	{
		NaverThirdPartyLoginConnection.getSharedInstance().delegate = viewModel.self
		NaverThirdPartyLoginConnection
        	.getSharedInstance()
			.requestThirdPartyLogin()
	} else { // 네이버 앱 안깔려져 있을때
		// Appstore에서 네이버앱 열기
		NaverThirdPartyLoginConnection.getSharedInstance().openAppStoreForNaverApp()

	}
} label : {
	Image("naver_login")
		.resizable()
		.aspectRatio(contentMode: .fit)
}

네이버 로그인은 카카오 로그인과 다르게 .requestThirdPartyLogin() 이 실행되면 앱 설치여부를 자동으로 판단해서 네이버 앱으로 이동 또는 웹 브라우져 모달을 띄우지만, 앱스토어 이동을 위해서 따로 조건을 나누어 주었습니다.

여기서 실제 데이터의 Flow

  • .requestThirdPartyLogin() 후 네이버 앱 또는 브라우져에서 네이버 계정1 로그인
  • 앱에 사용자 정보 제공을 위한 동의
  • Authorization Code를 담고 있는 URL을 가지고 앱으로 돌아옴 (Redirect)
  • .onOpenURL { ... } 에서 URL이 네이버 로그인을 위한 URL이라고 판단되면 .receiveAccessToken(url) 를 호출해서 토큰 발급

성공적으로 토큰을 발급받은 후 아까 구현한 Delegate 내의 oauth20ConnectionDidFinishRequestACTokenWithAuthCode() 가 실행됩니다.

유저 정보 받아오기

네이버 로그인 SDK 에서는 따로 유저정보를 받아오는 함수가 정의 되어있지 않습니다. 그래서 https 요청을 이용해서 정보를 받아올 수 있습니다. 아래는 Alamofire 를 이용해서 유저 정보를 요청하는 함수입니다.

func getUserInfo() {        
        guard let tokenType = NaverThirdPartyLoginConnection.getSharedInstance().tokenType else { return }
        guard let accessToken = NaverThirdPartyLoginConnection.getSharedInstance().accessToken else { return }
        let url = "https://openapi.naver.com/v1/nid/me"
        
        AF.request(url,
                   method: .get,
                   encoding: JSONEncoding.default,
                   headers: ["Authorization": "\(tokenType) \(accessToken)"]
        ).responseJSON { [weak self] response in
            guard let result = response.value as? [String: Any] else { return }
            guard let object = result["response"] as? [String: Any] else { return }
            
            guard let name = object["name"] as? String else { return }
            guard let email = object["email"] as? String else { return }
            guard let profileimage = object["profile_image"] as? String else { return }

            self?.profileImage = URL(string: profileimage)
            self?.userMail = email
            self?.userName = name
        }
    }

토큰 관련

// Refresh Token 
let refreshToken = NaverThirdPartyLoginConnection.getSharedInstance().refreshToken
// Access Toekn 
let accessToken = NaverThirdPartyLoginConnection.getSharedInstance().accessToken

// 유효한 Token 존재 여부 확인 
NaverThirdPartyLoginConnection.getSharedInstance().isValidAccessTokenExpireTimeNow()
// Token Refreshing
NaverThirdPartyLoginConnection.getSharedInstance().requestAccessTokenWithRefreshToken()

로그아웃 (토큰 삭제)

NaverThirdPartyLoginConnection.getSharedInstance().resetToken()

연결 끊기 (연동 해제)

NaverThirdPartyLoginConnection.getSharedInstance().requestDeleteToken()

마무리

SwiftUI 로 네이버 아이디로 로그인을 구현하는 방법을 알아보았습니다. 네이버 아이디로 로그인은 SDK 자체가 오래되기도 하였고, Objective-C 를 처음 봐서 신기하기도 했습니다😅

틀린 정보 또는 궁금한 점이 있다면 댓글 부탁드립니다! 읽어주셔서 감사합니다‼️

6개의 댓글

comment-user-thumbnail
2022년 8월 20일

앱 스토어 등록되지 않았으면 로그인 테스트를 할 수없는건가요 ?

1개의 답글
comment-user-thumbnail
2023년 2월 8일

초기화 부분에서 .isNaverThirdPartyLoginAppschemeURL(url) 를 통해 네이버 로그인 url인지 확인하시는데 해당 코드는 따로 선언한 임의의 코드인가요 아니면 NaverThirdPartyLogin 자체에서 지원하는 코드인가요? 계속 찾아보는데 해당되는 코드가 안보이네요 ㅠㅠ

2개의 답글
comment-user-thumbnail
2023년 5월 11일

감사합니다. 덕분에 네이버 로그인 쉽게 구성했습니다. 다만
} else { // 네이버 앱 안깔려져 있을때
// Appstore에서 네이버앱 열기
NaverThirdPartyLoginConnection.getSharedInstance().openAppStoreForNaverApp()
}
라는 부분이 있는데 웹으로 로그인을 구성하라고 리젝되었네요.
Guideline 4.2.3 - Design - Minimum Functionality

We were required to install the Naver app before we could log in to your app. Users should be able to log in and access their accounts without having to install any additional apps.

Next Steps

If you would like to offer authentication through Naver, please use a mechanism that allows users to log in from within your app without first having to install an additional app.

We recommend implementing the Safari View Controller API to display web content within your app. The Safari View Controller allows the display of a URL and inspection of the certificate from an embedded browser in an app so that customers can verify the webpage URL and SSL certificate to confirm they are entering their sign in credentials into a legitimate page.

Resources

For additional information on the Safari View Controller API, please review the What's New in Safari webpage.

저는 if, else 구분 없이 thirdLogin 을 실행하도록 수정하였습니다.
다시 한번 좋은 글 감사합니다~

답글 달기