맞춤 계정 유형 만들기

지금까지 Google에서 정의한 계정과 사용자를 사용하는 Google API 액세스에 관해 알아봤습니다. 하지만 자체 온라인 서비스가 있다면 이 서비스에 Google 계정이나 사용자가 없을 것입니다. 그렇다면 어떻게 해야 할까요? 사용자 기기에 새 계정 유형을 설치하는 것은 비교적 간단합니다. 이 과정에서는 기본 제공 계정과 동일한 방식으로 작동하는 맞춤 계정 유형을 만드는 방법을 설명합니다.

맞춤 계정 코드 구현하기

가장 먼저 필요한 것은 사용자로부터 사용자 인증 정보를 가져올 방법입니다. 이는 이름과 비밀번호를 요청하는 대화상자처럼 간단할 수 있습니다. 일회용 비밀번호나 생체 인식 스캔 같은 좀 더 이색적인 절차일 수도 있습니다. 어느 쪽이든 다음과 같은 코드를 구현하는 것은 개발자의 책임입니다.

  1. 사용자로부터 사용자 인증 정보 수집
  2. 서버에서 사용자 인증 정보 인증
  3. 기기에 사용자 인증 정보 저장

일반적으로 하나의 활동으로 위의 세 요건 모두를 처리할 수 있습니다. 이를 인증자 활동이라고 하겠습니다.

인증자 활동에는 AccountManager 시스템과 상호작용해야 하므로 일반 활동에는 없는 특정 요구사항이 있습니다. 올바른 작업을 수월하게 하기 위해 Android 프레임워크는 기본 클래스 AccountAuthenticatorActivity를 제공합니다. 이 클래스를 확장하여 자체 맞춤 인증자를 만들 수 있습니다.

인증자 활동의 처음 두 가지 요구사항인 사용자 인증 정보 수집과 인증을 해결하는 방법은 전적으로 사용자가 결정합니다. (방법이 한 가지뿐이라면 '맞춤' 계정 유형을 사용할 필요가 없었을 것입니다.) 세 번째 요구사항에는 비교적 간단한 표준 구현이 있습니다.

Kotlin

Account(username, your_account_type).also { account ->
    accountManager.addAccountExplicitly(account, password, null)
}

Java

final Account account = new Account(username, your_account_type);
accountManager.addAccountExplicitly(account, password, null);

스마트한 보안 접근 방식

AccountManager는 암호화 서비스나 키체인이 아니라는 점을 이해하는 것이 중요합니다. 개발자가 전달한 것처럼 계정 사용자 인증 정보를 일반 텍스트로 저장합니다. 대부분의 기기에서는 루트에서만 액세스할 수 있는 데이터베이스에 이를 저장하므로 특별한 문제가 아닙니다. 그러나 루팅된 기기에서는 기기에 대한 adb 액세스 권한이 있는 모든 사용자가 사용자 인증 정보를 읽을 수 있습니다.

이 점을 염두에 두고 사용자의 실제 비밀번호를 AccountManager.addAccountExplicitly()에 전달해서는 안 됩니다. 대신 공격자에게 제한적으로 사용할 수 있는 암호화 방식으로 안전한 토큰을 저장해야 합니다. 사용자 인증 정보가 중요한 정보를 보호하고 있다면 이와 유사한 작업을 신중하게 고려해야 합니다.

주의: 보안 코드에 관해서는 '집에서 따라 하지 마세요'라는 '신화 속의' 규칙을 따르세요. 맞춤 계정 코드를 구현하기 전에 보안 전문가에게 문의하세요.

이제 보안 면책조항은 처리되었으므로 본격적으로 작업하겠습니다. 이미 맞춤 계정 코드의 핵심을 구현했으므로 이제 남은 것은 연결입니다.

AbstractAccountAuthenticator 확장하기

AccountManager가 맞춤 계정 코드와 함께 작동하려면 AccountManager가 예상하는 인터페이스를 구현하는 클래스가 필요합니다. 이 클래스가 인증자 클래스입니다.

인증자 클래스를 만드는 가장 쉬운 방법은 AbstractAccountAuthenticator를 확장하고 추상 메서드를 구현하는 것입니다. 이전 과정을 진행해 보았다면 AbstractAccountAuthenticator의 추상 메서드에 익숙할 것입니다. 이전 과정에서 계정 정보와 승인 토큰을 가져오기 위해 호출한 메서드의 반대쪽에 있는 메서드입니다.

인증자 클래스를 올바르게 구현하려면 여러 개의 개별 코드가 필요합니다. 첫째, AbstractAccountAuthenticator에는 재정의해야 하는 추상 메서드가 7개 있습니다. 둘째, "android.accounts.AccountAuthenticator"인텐트 필터를 애플리케이션 매니페스트에 추가해야 합니다 (다음 섹션 참고). 마지막으로, 맞춤 계정 유형의 이름과 시스템에서 이 유형의 계정 옆에 표시할 아이콘을 정의하는 두 개의 XML 리소스를 제공해야 합니다.

성공적인 인증자 클래스와 XML 파일을 구현하는 단계별 안내를 AbstractAccountAuthenticator 문서에서 확인할 수 있습니다.

인증자 활동에 특수한 초기화 매개변수가 필요한 경우 Intent.putExtra()를 사용하여 인텐트에 매개변수를 연결할 수 있습니다.

인증자 서비스 만들기

이제 만든 인증자 클래스를 배치할 장소가 필요합니다. 계정 인증자는 여러 애플리케이션에 사용할 수 있어야 하고 백그라운드에서 작동해야 하므로 당연히 Service 내에서 실행되어야 합니다. 이를 인증자 서비스라고 하겠습니다.

인증자 서비스는 아주 단순할 수 있습니다. 인증자 클래스의 인스턴스를 onCreate()에 만들고 onBind()에서 getIBinder()를 호출하기만 하면 됩니다.

매니페스트 파일에 <service> 태그를 추가하고 AccountAuthenticator 인텐트의 인텐트 필터를 추가하고 계정 인증자를 선언해야 합니다.

<service ...>
   <intent-filter>
      <action android:name="android.accounts.AccountAuthenticator" />
   </intent-filter>
   <meta-data android:name="android.accounts.AccountAuthenticator"
             android:resource="@xml/authenticator" />
</service>

서비스 배포하기

모두 마쳤습니다! 이제 시스템에서 'Google' 및 'Corporate' 같은 모든 유명 계정 유형과 함께 계정 유형을 인식합니다. 계정 및 동기화 설정 페이지를 사용하여 계정을 추가할 수 있으며 맞춤 유형의 계정을 요청하는 앱은 다른 계정 유형과 마찬가지로 열거하고 인증할 수 있습니다.

물론, 이러한 모든 부분에서는 계정 서비스가 실제로 기기에 설치되어 있다고 가정합니다. 단 하나의 앱만 서비스에 액세스한다면 이는 별 문제가 되지 않습니다. 앱에 서비스를 번들로 묶기만 하면 됩니다. 그러나 둘 이상의 앱에서 계정 서비스를 사용하도록 하려면 작업이 더 까다로워집니다. 서비스를 모든 앱과 함께 번들로 묶어 여러 앱의 사본이 사용자 기기의 공간을 차지하도록 해서는 안 됩니다.

한 가지 해결책은 특수 목적의 소규모 APK 하나에 서비스를 배치하는 것입니다. 앱이 맞춤 계정 유형을 사용하려고 하면 기기에서 맞춤 계정 서비스를 사용할 수 있는지 확인할 수 있습니다. 그렇지 않은 경우 사용자를 Google Play로 안내하여 서비스를 다운로드할 수 있습니다. 처음에는 큰 문제가 생긴 것처럼 보일 수 있지만, 맞춤 계정을 사용하는 모든 앱에 사용자 인증 정보를 다시 입력하는 대안과 비교하면 아주 쉽습니다.