말랑한 하루

[Flutter] OAuth, Kakao Login 개발 본문

개발/Flutter

[Flutter] OAuth, Kakao Login 개발

지수는말랑이 2024. 3. 30. 19:28
반응형

※ reference : https://developers.kakao.com/docs/latest/ko/kakaologin/flutter

※ design : https://developers.kakao.com/docs/latest/ko/kakaologin/design-guide

 

Kakao developers의 개발 및 디자인 가이드에 따라 kakaologin을 시작합니다.

 

🥕 설치

※ reference : https://developers.kakao.com/docs/latest/ko/flutter/getting-started#apply-sdk

$ flutter pub add kakao_flutter_sdk
$ flutter pub get

 

🥕 애플리케이션 정보

※ reference : https://developers.kakao.com/console/app

 

kakaologin을 시작하기에 앞서 내 애플리케이션 항목에서 애플리케이션을 추가하여 관련 정보를 얻어야합니다.

 

🥕 초기화

※ reference : https://developers.kakao.com/docs/latest/ko/flutter/getting-started#init

 

애플리케이션에서 다운로드 받은 Flutter SDK를 초기화 시키는 것이 첫 작업입니다.

main()에서 runApp()을 호출하기 전, KakaoSdk를 초기화합니다.

void main() async {
  await dotenv.load(fileName: '.env');

  KakaoSdk.init(
    nativeAppKey: dotenv.get('KAKAO_NATIVE_APP_KEY'),
  );

  runApp(MyApp());
}

관련 Key는 노출되지 않도록 dotenv 라이브러리를 활용하거나 개별적으로 관리하세요.

 

또한, Flutter의 minSdkVersion이 21보다 낮은 경우에 버전 문제를 일으킬 수 있습니다. android/app/build.gradle 경로의 android/defaultConfig 속성에 minSdkVersion을 21로 설정하세요

 

🥕 프로젝트 설정

 

🍒 인터넷 사용 권한

Flutter Project/android/app/src/AndroidManifest.xml 파일의 <manifest> Element 하위에 인터넷 사용 권한을 설정하는 <uses-permission> Element를 추가합니다.

<uses-permission android:name="android.permission.INTERNET" />

 

🍒 커스텀 URL 스킴

※ reference : https://developers.kakao.com/docs/latest/ko/flutter/getting-started#project-scheme

 

커스텀 URL 스킴(Custom URL Scheme)은 사용자가 Android와 iOS 환경에서 카카오톡으로 로그인 후 서비스 앱으로 돌아오거나, 카카오톡 메시지 버튼 또는 링크로 서비스의 앱을 실행하는 데 사용됩니다.

 

🍇 Android

Flutter Project/android/app/src/AndroidManifest.xml 파일을 수정합니다.

 

단, AndroidManifest.xml 파일을 수정할 때 생성하는 <activity> Element에 대해 Android 12(API 31) 이상을 타깃하는 경우, android:exported 속성을 반드시 true로 선언해주어야 합니다.

 

🍌 카카오 로그인

<application> Element 하위에 카카오 로그인 Redirect URI 설정을 위한 <activity> Element를 추가합니다.

<!-- 카카오 로그인 커스텀 URL 스킴 설정 -->
<activity 
    android:name="com.kakao.sdk.flutter.AuthCodeCustomTabsActivity"
    android:exported="true">
    <intent-filter android:label="flutter_web_auth">
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />

        <!-- "kakao${YOUR_NATIVE_APP_KEY}://oauth" 형식의 앱 실행 스킴 설정 -->
        <!-- 카카오 로그인 Redirect URI -->
        <data android:scheme="kakao${YOUR_NATIVE_APP_KEY}" android:host="oauth"/>
    </intent-filter>
</activity>

🍌 카카오톡 공유, 카카오톡 메세지

android:name=".MainActivity" 속성을 갖는 <activity> Element 하위에 다음 <data> Element를 포함하는 <intent-filter> Element를 추가합니다.

 

대부분의 경우 <intent-filter> Element가 존재하므로, 내부 <data> Element에 대해서만 추가할 수 있습니다.

<intent-filter>
	<data android:host="kakaolink" android:scheme="kakao${YOUR_NATIVE_APP_KEY}" />
</intent-filter>

🍌 API KEY 관리

Flutter Project의 android 폴더 하위에는 local.properties 파일이 있습니다. 대부분의 경우 이 폴더에서 api key를 추가적으로 관리합니다.

 

local.properties 파일에서 api key를 작성하였다면, Flutter Project/android/app경로의 build.gradle에서 BuildConfig에 변수를 추가하면 완료입니다.

 

local.properties를 build.gradle에서 사용하기 위해 다음과 같이 properties 객체를 생성합니다.

def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')

이후, android>defaultConfig에 manifestPlaceholder를 활용하여 api key에 대한 변수를 지정합니다.

 

※ reference : https://developer.android.com/build/manage-manifests?hl=ko&_gl=1*1pzo7kg*_up*MQ.._gaMTMxMzcyODE0LjE3MDg5MzM5MDI._ga_6HH9YJMN9MMTcwODkzMzkwMS4xLjAuMTcwODkzMzkwMS4wLjAuMA..#inject_build_variables_into_the_manifest

 

Android의 기본 manifestPlaceholders가 존재하기 때문에, 공식문서처럼 대입하는 것이 아닌 다음과 같이 값을 추가해주어야 한다.

manifestPlaceholders += [KAKAO_NATIVE_APP_KEY:localProperties.getProperty('api.key.kakao.nativeApp')]

 

🍇 iOS 커스텀 URL 스킴

iOS 디바이스에서는 커스텀 URL 스킴을 사용하기 위해선 Xcode를 활용한 두 개의 설정이 필요합니다.

 

🍌 앱 실행 허용 목록

🍌 URL Schemes

 

🥕 구현

※ reference : https://developers.kakao.com/docs/latest/ko/kakaologin/flutter#before-you-begin-type-implementation

 

Flutter SDK에서는 다양한 서비스 환경에 대응할 수 있도록 여러가지 구현 방식을 제공하고 있으나, 현재 파트에서는 권장 사항인 네이티브 앱 서비스에서 카카오톡으로 로그인방식을 진행하는 경우를 다룹니다.

 

※ Kakao 로그인을 사용하기 위한 최소 SDK 버전은 21입니다. android/app/build.gradle의 android→defaultConfig→minSdkVersion을 21로 설정하세요.

 

🍒 사전 설정

※ reference : https://developers.kakao.com/docs/latest/ko/kakaologin/flutter#login-with-kakaotalk

 

조건부 및 선택형 설정을 제외한 사전 필수 설정 항목은 다음과 같습니다.

 

🍇 플랫폼 등록

※ reference : https://developers.kakao.com/docs/latest/ko/getting-started/app#platform

 

내 애플리케이션> 앱 설정> 플랫폼 경로를 통해 Android/iOS 플랫폼 등록을 진행합니다.

android/app/src/main/AndroidManifest.xml 파일의 package 속성 값과 일치한지 확인합니다.

또한 키 해시 값이 등록되어 있는지 확인합니다.

 

※ reference : https://developers.kakao.com/docs/latest/ko/android/getting-started#before-you-begin-add-key-hash

 

키 해시(Key Hash)는 인증서(Certificate)의 인증서 지문 값(Certificate fingerprints)을 해시(hash)한 값으로, 악성 앱인지 판별하고 카카오 API를 호출하기 위해 사용됩니다. 키 해시 값은 변경되지 않으나, 여러 개발자들과 함께하는 경우 각 개발자들의 개발 환경에 따라 디버그 키스토어가 다르게 생성되어 있으므로 모두 등록해주어야 합니다.

 

카카오 API를 호출하면, 카카오 API 서버가 요청 헤더에 추가된 키 해시값과 카카오 플랫폼에 등록한 값이 일치하는지 확인하며, 디버그(Debug)/릴리즈(Release) 키 해시 두 가지가 있습니다.

 

※ reference : https://code.google.com/archive/p/openssl-for-windows/downloads

 

다음과 같이 터미널에서 키 해시를 생성하려면 키 해시를 관리하는 키툴(keytool)이 필요합니다. Windows의 경우, Windows 라이브러리를 위한 OpenSSL을 다운로드해야 합니다.

OpenSSL을 사용할 때는, openssl.exe가 존재하는 폴더의 경로를 입력하여 실행될 수 있게 만들어줍니다.

 

🍌 Debug Key Hash

keytool -exportcert -alias androiddebugkey -keystore %USERPROFILE%\\.android\\debug.keystore -storepass android -keypass android 
> | ${path}\\openssl sha1 -binary | ${path}\\openssl base64

🍌 Release Key Hash

 

🍇 카카오 로그인 활성화 설정

※ reference : https://developers.kakao.com/docs/latest/ko/kakaologin/prerequisite#kakao-login-activate

 

내 애플리케이션> 제품 설정> 카카오 로그인 경로를 통해 카카오 로그인 활성화 설정을 ON으로 변경합니다.

 

🍇 동의항목

※ reference : https://developers.kakao.com/docs/latest/ko/kakaologin/prerequisite#consent-item

 

내 애플리케이션> 제품 설정> 카카오 로그인> 동의항목에서 카카오 로그인 시 사용자에게 동의받고자 하는 항목을 설정할 수 있습니다. 카카오 로그인 동의 화면에 반영되며, 사용자는 서비스 이용시 필요한 동의항목에 동의할 수 있습니다.

 

동의 항목을 추가하는 경우, 동의 목적을 반드시 작성해야 합니다.

 

🍒 로그인 요청

※ reference : https://developers.kakao.com/docs/latest/ko/kakaologin/flutter#kakaologin-sample

 

로그인 요청은 기존 로그인을 통해 발급받은 토큰이 있는지 확인하거나, isKakaoTalkInstalled()메소드로 카카오톡 실행 가능 여부를 판단하는 방법이 있습니다.

void KakaoLogin() async {
  // 카카오톡 실행 가능 여부 확인
  // 카카오톡 실행이 가능하면 카카오톡으로 로그인, 아니면 카카오계정으로 로그인
  bool result = await isKakaoTalkInstalled();
  if (await isKakaoTalkInstalled()) {
    print("카카오톡 있음");
    try {
      await UserApi.instance.loginWithKakaoTalk();
      print('카카오톡으로 로그인 성공');
    } catch (error) {
      print('카카오톡으로 로그인 실패 $error');

      // 사용자가 카카오톡 설치 후 디바이스 권한 요청 화면에서 로그인을 취소한 경우,
      // 의도적인 로그인 취소로 보고 카카오계정으로 로그인 시도 없이 로그인 취소로 처리 (예: 뒤로 가기)
      if (error is PlatformException && error.code == 'CANCELED') {
        return;
      }
      // 카카오톡에 연결된 카카오계정이 없는 경우, 카카오계정으로 로그인
      try {
        await UserApi.instance.loginWithKakaoAccount();
        print('카카오계정으로 로그인 성공');
      } catch (error) {
        print('카카오계정으로 로그인 실패 $error');
      }
    }
  } else {
    print("카카오톡 없음");
    try {
      OAuthToken token = await UserApi.instance.loginWithKakaoAccount();
      print('카카오계정으로 로그인 성공');
    } catch (error) {
      print('카카오계정으로 로그인 실패 $error');
    }
  }
}

Kakao 로그인을 에뮬레이터 활용하여 테스트할 때, API 12버전 이상인 경우 "동의하고 계속하기" 부분에서 버그(화면이 표기되지 않는 현상/화면 깜박임 현상)가 발생한다고 합니다.

 

(https://devtalk.kakao.com/t/topic/134052/2) 이 점 참고하여 에뮬레이터 설정을 변경하세요.

 

🍒 토큰

※ reference : https://developers.kakao.com/docs/latest/ko/kakaologin/flutter#request-token

 

토큰은 액세스 토큰(Access token), 리프레시 토큰(Refresh token), ID 토큰(ID token) 세 종류입니다.

액세스 토큰을 활용하면 토큰 정보를 보거나 ID 토큰 유효성 검증을 진행할 수 있습니다.

 

서비스 서버에서 토큰을 발급받은 후, 서비스 서버에서 액세스 토큰으로 사용자 정보 가져오기를 호출해 회원 가입 및 로그인에 필요한 사용자 정보를 요청할 수 있습니다. 액세스 토큰을 서비스 클라이언트로 전달해 토큰 할당하면, 서비스 클라이언트에서 Flutter SDK를 통한 카카오 API 요청에 사용할 수 있습니다.

 

🍇 토큰 확인

※ reference : https://developers.kakao.com/docs/latest/ko/kakaologin/flutter#token-presence

 

AuthAPI의 hasToken()을 호출하여 Flutter SDK에 기존에 발급받아 저장된 토큰이 있는지 확인합니다.

저장된 토큰이 있는 경우, 앱을 실행하거나 카카오 로그인이 필요한 API를 호출하기 전 검증하여 다음 행위를 진행하는데 도움을 줄 수 있습니다.

 

🍇 토큰 정보 보기

※ reference : https://developers.kakao.com/docs/latest/ko/kakaologin/flutter#get-token-info

 

UserApi의 accessTokenInfo()를 호출하여 Flutter SDK에 저장중인 액세스 토큰의 정보를 조회합니다. 요청 성공 시, 앱ID/회원번호/남은 유효시간 정보를 담은 AccessTokenInfo 객체가 반환됩니다. 액세스 토큰이 만료되었거나 존재하지 않는 경우에는 에러를 반환하므로, 기존 액세스 토큰의 만료 여부를 확인하는 용도로도 사용할 수 있습니다.

if (await AuthApi.instance.hasToken()) {
	try {
	  AccessTokenInfo tokenInfo = await UserApi.instance.accessTokenInfo();
	  print('토큰 유효성 체크 성공 ${tokenInfo.id} ${tokenInfo.expiresIn}');
	} catch (error) {
	  if (error is KakaoException && error.isInvalidTokenError()) {
	    print('토큰 만료 $error');
	  } else {
	    print('토큰 정보 조회 실패 $error');
	  }
	
	  try {
	    // 카카오계정으로 로그인 = 새로운 토큰 발급
	    OAuthToken token = await UserApi.instance.loginWithKakaoAccount();
	    print('로그인 성공 ${token.accessToken}');
	  } catch (error) {
	    print('로그인 실패 $error');
	  }
	}
} 

결과가 true인 이후에도 토큰이 유효한지 확인해야 합니다. 토큰이 유효하지 않다면 다시 카카오 로그인을 통해 새로운 토큰 발급을 진행해야 합니다.

 

🍒 사용자 정보 가져오기

※ reference : https://developers.kakao.com/docs/latest/ko/kakaologin/flutter#req-user-info

 

로그인에 성공하고 토큰 유효성 검증이 끝났다면, UserApi의 me()를 호출하여 사용자의 정보를 불러옵니다.

try {
  User user = await UserApi.instance.me();
  print('사용자 정보 요청 성공'
        '\\n회원번호: ${user.id}'
        '\\n닉네임: ${user.kakaoAccount?.profile?.nickname}'
        '\\n이메일: ${user.kakaoAccount?.email}');
} catch (error) {
  print('사용자 정보 요청 실패 $error');
}

 

🍒 로그아웃

※ reference : https://developers.kakao.com/docs/latest/ko/kakaologin/flutter#logout

 

로그아웃은 성공 여부와 상관 없이 Flutter SDK에 저장된 사용자 토큰 정보를 삭제합니다. 토큰이 삭제되는 경우, 현재 토큰 값을 통해 카카오 API를 호출할 수 없습니다.

try {
  await UserApi.instance.logout();
  print('로그아웃 성공, SDK에서 토큰 삭제');
} catch (error) {
  print('로그아웃 실패, SDK에서 토큰 삭제 $error');
}

 

🍒 연결 끊기

※ reference : https://developers.kakao.com/docs/latest/ko/kakaologin/flutter#unlink

 

요청 성공 시, 앱과 연결이 해제된 사용자의 회원번호를 포함한 UserIdResponse 객체가 반환됩니다. 또한 로그아웃 처리가 함께 이뤄져 Flutter SDK에 저장된 토큰이 삭제됩니다.

try {
  UserIdResponse = await UserApi.instance.unlink();
  print('연결 끊기 성공, SDK에서 토큰 삭제');
} catch (error) {
  print('연결 끊기 실패 $error');
}

로그아웃과 연결 끊기는, Flutter SDK에 저장된 카카오 토큰 정보를 삭제하는 행위입니다.

반응형
Comments