호댕의 iOS 개발

[iOS] OAuth를 활용한 카카오톡 소셜 로그인 구현 본문

Software Engineering/iOS

[iOS] OAuth를 활용한 카카오톡 소셜 로그인 구현

호르댕댕댕 2022. 3. 20. 22:15

🔔 야곰아카데미 토요 스터디에서 진행한 내용입니다.

최근 앱을 사용하다보면 Google / Naver / Kakao / Facebook을 통한 소셜 로그인 기능을 자주 볼 수 있다. 

이런 소셜 로그인이 어떻게 구현되는지 간단하게 살펴보고 직접 카카오를 통한 소셜 로그인 기능을 구현해보자. 

 

일단 직접 구현하는 방법을 살펴보기 전에 OAuth가 어떤 기능인지 살펴보자. 

 

🪢 OAuth

📚 정의

사용자(개발자 및 회사)들이 제 3사의 서비스를 사용하기 위해 사용하는 개념으로 위임 / 인가 / 허가 프로토콜이다. 
이는 단순한 인증 프로토콜이 아니기 때문에 단순히 `소셜 로그인 = OAuth`라고 보기에는 무리가 있다

다만 누군가에게 허가 / 위임 / 인가를 하기 위해선 본인을 증명해야 다른 사람에게 본인의 권한을 줄 수 있다. 온라인 상에서의 인증은 로그인 / 인증번호 입력 등의 방법이 있다.

 

따라서 인증의 과정을 통해 본인임을 증명하고 본인을 대리하여 다른 사람이 특정 Action을 처리할 수 있도록 하는 것이 OAuth인 것이다. 

그렇다면 이런 과정이 어떻게 이뤄지는지 그림으로 살펴보자.

OAuth는 그림에서 보이다시피 3명의 주체에 의해 작동을 한다. 

그 주체는 다음과 같다. 

  • 사용자: 특정 앱을 사용하는 사용자를 의미
  • Client: 특정 앱을 운영하는 기업이나 개인을 의미
  • 서비스 제공자(위 그림에선 카카오톡): 카카오 / 네이버 / 페이스북 / 구글 등의 기업

 

❓ 그렇다면 왜 이런 개념을 사용하게 된 것일까? 

Client가 만약 작은 기업이라면 특정 서비스를 제공하기 위해 개인 정보나 특정 기능을 어디서 끌고 와야 하는데 이미 카카오 / 네이버 / 페이스북 / 구글은 이런 정보와 기능을 가진 경우가 많다. 따라서 Client는 서비스 제공자인 기업에게 OAuth를 요청하게 되는 것이다. 

 

그렇다면 서비스 제공자는 왜 이런 기능과 정보를 제공해주는 것일까?

서비스 제공자 또한 Client를 통해 사용자가 서비스 제공자에게 ID를 만들고 계속 이를 유지하도록 하는 유인을 제공할 수 있다.

Client같은 기업들이 많아지고 사용자 또한 이렇게 OAuth 기능을 사용한다면 특정 서비스를 사용하기 위해서라도 서비스 제공자의 서비스에 계속 가입할 수 밖에 없는 것이다. 

 

사용자 또한 다양한 기업에게 직접 ID와 비밀번호를 생성하며 서비스를 사용하기 보단 하나의 계정만 관리하면 된다는 편리함 때문에 OAuth를 사용하게 된다. 

 

즉, 세 명의 주체 모두에게 주는 장점이 존재하는 기술인 것이다. 

 

 

🔨 카카오톡 로그인 기능 구현

그렇다면 지금부터 카카오톡 로그인 기능은 어떻게 구현하는지 살펴보자. 

물론 Kakao Developers에 자세히 나와있긴 하지만 정리를 해보고자 한다.

 

Kakao Developers

카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.

developers.kakao.com

 

1️⃣ Kakao Developers '내 애플리케이션'에 앱 추가

일단 카카오톡 로그인 기능을 추가할 어플리케이션을 추가해줘야 한다. (참고 링크)

 

여기서는 요구하는 내용을 작성해주고 '저장'을 누르면 된다. 

작성한 내용은 추후 사용자가 카카오톡 로그인하기를 통해 동의 항목을 선택하는 화면에서 표시되게 된다. 

 

이렇게 앱을 생성해주게 되면 App Key가 발급된다. 

(네이티브 / REST API / JavaScript / Admin)

그리고 현재는 iOS 전용 앱을 만들 예정이기 때문에 플랫폼을 iOS로 등록해주면 된다. 

 

2️⃣ KakaoSDK 라이브러리 추가하기 

코코아팟 혹은 SPM을 통해 KakaoSDK 라이브러리를 설치해주면 된다. 

RxSwift를 위한 라이브러리도 따로 존재하니 만약 RxSwift를 적용하는 프로젝트라면 해당 라이브러리를 설치해주면 된다.

3️⃣ 앱 실행 허용 목록 설정하기 

Project의 Targets에 있는 Info 설정을 해주면 된다. 

 

Custom iOS Target PropertiesLSApplicationQueriesSchemes(Array)를 추가하고 item으로 "kakaokompassauth(String)", "kakaolink(String)"를 추가해주면 된다. 

 

해당 설정은 iOS의 사용자 정보 보호 정책을 위해 필요한 설정이다.

(현재는 카카오톡 앱이 있을 경우에만 로그인을 할 수 있도록 kakaokompassauth만 등록해주긴 했다)

 

이는 Info.plist에서도 소스코드로 적용할 수 있다.

 <key>LSApplicationQueriesSchemes</key>
  <array>
      <!-- 카카오톡으로 로그인 -->
      <string>kakaokompassauth</string>
      <!-- 카카오링크 -->
      <string>kakaolink</string>
  </array>

 

4️⃣ URL Schemes 설정하기

이 또한 Project의 Targets에 있는 Info 설정을 해주면 된다. 

여기서 URL Types를 열어 URL Schemes를 설정해줘야 한다. 

 

❗️여기서 중요한 점!!!!! ❗️

URL Schemes에선 반드시 App Key (네이티브 앱 키 사용) 앞에 kakao를 붙여줘야 한다!!

 

얘를 안 붙이면 로그인 화면으로는 넘어가나 다시 앱으로 돌아오지 않는 문제가 발생한다. 물론 카카오 공식 문서에서 친절하게 알려주고 있긴 하다... 나는 이걸 자세히 안보고 이것 때문에 한~~참 삽질을 했다.

공식 문서에 뻔히 나와있는 걸 못보고... 반성한다... 나 자신... 🥲

 

이를 통해 카카오톡으로 로그인 후 서비스 앱으로 돌아오는데 사용되며, 카카오 링크 메시지 또는 카카오 스토리 게시물을 통해 앱을 실행할 때 사용이 된다. 

(형식은 아래와 같다)

 

  • 카카오 로그인 : kakao${NATIVE_APP_KEY}://oauth
  • 카카오 링크 : kakao${NATIVE_APP_KEY}://kakaolink
  • 카카오 스토리 : kakao${NATIVE_APP_KEY}://kakaostory

 

5️⃣ AppDelegate에서 네이티브 앱 키를 사용해 SDK 초기화하기 

import KakaoSDKCommon

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

  ...
  KakaoSDK.initSDK(appKey: "${NATIVE_APP_KEY}")
  ...

}

❗️여기서 중요한 점!!!!! ❗️

이때 또 주의할 점은 URLScheme을 설정할 때에는 App Key (네이티브 앱 키 사용) 앞에 kakao를 붙여줘야 했는데 여기서는 그냥 앱키를 바로 적어주면 된다. 

 

6️⃣ 카카오톡으로 로그인을 위한 필수 설정 

iOS 13 이후 SceneDelegate가 생기면서 설정은 SceneDelegate에서 해주면 된다. 

import KakaoSDKAuth


class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?
    
    func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
        if let url = URLContexts.first?.url {
            if (AuthApi.isKakaoTalkLoginUrl(url)) {
                _ = AuthController.handleOpenUrl(url: url)
            }
        }
    }
    
    •••
}

만약 iOS 13 전을 사용한다면 AppDelegate에 다음과 같이 함수를 선언해주면 된다.

 

func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
    if (AuthApi.isKakaoTalkLoginUrl(url)) {
        return AuthController.handleOpenUrl(url: url)
    }

    return false
}

 

 

7️⃣ '내 애플리케이션' 설정

일단 카카오 로그인 기능을 활성화해줘야 하기 때문에 제품설정 > 카카오 로그인에 들어가서 활성화를 해줘야 한다. 

 

그리고 동의 항목에 필요한 부분에 대해 동의를 받는다고 설정을 하고 왜 동의를 받아야 하는지 이유를 작성해주면 끝이다!! 

 

그럼 이제 직접 카카오 로그인 UI를 받고 로그인을 하면 어떤 Action을 할 지 정해주면 된다. 

 

8️⃣ 로그인을 했을 때 Action 구현하기

일단 카카오에서 제공하는 로그인 이미지를 사용해야 하기 때문에 링크의 이미지를 받아서 사용했다. 

물론 커스텀도 할 수는 있지만 이 때도 카카오 고유의 이미지는 유지할 수 있도록 제작을 해야 한다고 안내를 하고 있다. (관련 링크)

 

일단 ViewController의 코드는 다음과 같다. 

(전체 코드는 https://github.com/yanghojoon/WeekPractice-OAuth에 업로드해놓았습니다)

 

GitHub - yanghojoon/WeekPractice-OAuth: 야곰 아카데미 토요 스터디에서 진행한 소셜 로그인 관련 내용입

야곰 아카데미 토요 스터디에서 진행한 소셜 로그인 관련 내용입니다. . Contribute to yanghojoon/WeekPractice-OAuth development by creating an account on GitHub.

github.com

import UIKit
import KakaoSDKUser


class ViewController: UIViewController {
    @IBOutlet weak var profileImageView: UIImageView!
    @IBOutlet weak var nicknameLabel: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }

    @IBAction func touchUpKakaoTalkLoginButton(_ sender: UIButton) {
        if (UserApi.isKakaoTalkLoginAvailable()) {
            print("로그인 사용 가능")
            UserApi.shared.loginWithKakaoTalk {(oauthToken, error) in 
                if let error = error {
                    print(error)
                }
                else {
                    print("loginWithKakaoTalk() success.")

                    UserApi.shared.me { user, error in
                        if let error = error {
                            print(error)
                        } else {
                            let profileImageURL = user?.kakaoAccount?.profile?.profileImageUrl
                            let nickname = user?.kakaoAccount?.profile?.nickname
                            
                            self.presentProfile(profileURL: profileImageURL, nickname: nickname)
                        }
                    }
                }
            }
        } else {
            print("로그인 실패") // 시뮬레이터에선 앱이 없어서 지금 계속 실패를 하는 중
        }
    }
    
    private func presentProfile(profileURL: URL?, nickname: String?) {
        guard let imageData = try? Data(contentsOf: profileURL!) else { return }
        
        profileImageView.image = UIImage(data: imageData)
        nicknameLabel.text = nickname
    }
    
}

로그인을 하면 단순히 프로필 사진과 닉네임만 가지고 오는 것이었기에 코드는 간단하다. 

 

일단 여기서 UserApiKakaoSDKUser에 정의되어 있는 타입으로 카카오 Open API에서 API 호출을 담당하는 클래스이다. 

여기서 isKakaoTalkLoginAvailable()메서드의 경우 로그인을 했을 때 UIApplication.shared.canOpenURL() 메소드를 사용하여 현재 간편 로그인이 가능한지 확인을 하게 된다. 

 

즉, 현재는 카카오톡 앱이 있는 경우만 실행이 되게 해놨기 때문에 카카오톡 앱이 없다면 해당 메서드에서 false가 반환되게 된다. 

그러므로 카카오톡이 따로 깔려있지 않은 시뮬레이터에서는 항상 false가 나오게 된다. 

만약 카카오톡을 실행할 수 없거나 아예 앱이 없는 경우에는 loginWithKakaoAccount()로 웹 로그인을 시도할 수도 있다.

 

만약 이를 통과했다면 loginWithKakaoTalk(channelPublicIds:serviceTerms:nonce:completion:)를 실행하게 된다. 해당 메스드는 토큰과 에러를 받는 completion을 사용할 수 있다. 여기서 에러가 났을 경우와 정상적으로 로그인이 된 경우 어떻게 처리할 지를 작성해줄 수 있다. 

 

현재는 프로필 이미지와 닉네임만 받고 싶기 때문에 사용자에 대한 다양한 정보를 얻을 수 있는 me(propertyKeys:secureResource:completion:)  메서드를 사용했다. 

이를 통해 user의 프로필 이미지와 닉네임에 접근해서 현재 Label과 ImageView에 넣어주도록 구현을 해보았다. 

 

이외에도 다양한 메서드들이 있으니 궁금하신 분들은 여기서 찾아보세요! 

 


카카오에선 문서를 잘 정리해두었지만 문서를 꼼꼼히 보지 않았더니 한참 헤매긴 했다... 

 

앞으로도 항상 공식 문서는 꼼꼼히 살펴봐야겠다... ㅎ...

Comments