다음을 통해 공유


자습서: Android(Kotlin) 모바일 앱에서 사용자 로그인

이는 Microsoft Entra 외부 ID를 사용하여 사용자를 로그인하는 방법을 안내하는 자습서 시리즈의 세 번째 자습서입니다.

이 자습서에서는 다음을 수행합니다.

  • 사용자 로그인
  • 사용자 로그 아웃

필수 조건

자습서: 인증을 위해 Android 앱을 준비합니다.

사용자 로그인

Android용 MSAL(Microsoft 인증 라이브러리)을 사용하여 사용자를 로그인하는 데는 토큰을 대화형으로 획득하거나 자동으로 획득하는 두 가지 주요 옵션이 있습니다.

  1. 사용자가 대화형으로 로그인하도록 하려면 다음 코드를 사용합니다.

        private fun acquireTokenInteractively() {
        binding.txtLog.text = ""
    
        if (account != null) {
            Toast.makeText(this, "An account is already signed in.", Toast.LENGTH_SHORT).show()
            return
        }
    
        /* Extracts a scope array from text, i.e. from "User.Read User.ReadWrite" to ["user.read", "user.readwrite"] */
        val scopes = scopes.lowercase().split(" ")
        val parameters = AcquireTokenParameters.Builder()
            .startAuthorizationFromActivity(this@MainActivity)
            .withScopes(scopes)
            .withCallback(getAuthInteractiveCallback())
            .build()
    
        authClient.acquireToken(parameters)
    }
    

    코드는 Android용 MSAL을 사용하여 대화형으로 토큰을 획득하는 프로세스를 시작합니다. 먼저 텍스트 로그 필드를 지웁니다. 그런 다음 이미 로그인된 계정이 있는지 확인하고, 그렇다면 계정이 이미 로그인되어 있음을 알리는 알림 메시지를 표시하고 돌아옵니다.

    다음으로, 텍스트 입력에서 범위를 추출하고 이를 소문자로 변환한 후 배열로 분할합니다. 이러한 범위를 사용하여 현재 활동에서 권한 부여 프로세스 시작 및 콜백 지정을 포함하여 토큰 획득을 위한 매개 변수를 빌드합니다. 마지막으로 토큰 획득 프로세스를 시작하기 위해 구성된 매개 변수를 사용하여 인증 클라이언트에서 acquireToken()을 호출합니다.

    콜백을 지정하는 코드에서는 getAuthInteractiveCallback()이라는 함수를 사용합니다. 함수에는 다음 코드가 있어야 합니다.

    private fun getAuthInteractiveCallback(): AuthenticationCallback {
        return object : AuthenticationCallback {
    
            override fun onSuccess(authenticationResult: IAuthenticationResult) {
                /* Successfully got a token, use it to call a protected resource - Web API */
                Log.d(TAG, "Successfully authenticated")
                Log.d(TAG, "ID Token: " + authenticationResult.account.claims?.get("id_token"))
                Log.d(TAG, "Claims: " + authenticationResult.account.claims
    
                /* Reload account asynchronously to get the up-to-date list. */
                CoroutineScope(Dispatchers.Main).launch {
                    accessToken = authenticationResult.accessToken
                    getAccount()
    
                    binding.txtLog.text = getString(R.string.log_token_interactive) +  accessToken
                }
            }
    
            override fun onError(exception: MsalException) {
                /* Failed to acquireToken */
                Log.d(TAG, "Authentication failed: $exception")
    
                accessToken = null
                binding.txtLog.text = getString(R.string.exception_authentication) + exception
    
                if (exception is MsalClientException) {
                    /* Exception inside MSAL, more info inside MsalError.java */
                } else if (exception is MsalServiceException) {
                    /* Exception when communicating with the STS, likely config issue */
                }
            }
    
            override fun onCancel() {
                /* User canceled the authentication */
                Log.d(TAG, "User cancelled login.");
            }
        }
    }
    

    코드 조각은 AuthenticationCallback의 인스턴스를 반환하는 getAuthInteractiveCallback 함수를 정의합니다. 이 함수 내에서 AuthenticationCallback 인터페이스를 구현하는 익명 클래스가 만들어집니다.

    인증이 성공하면(onSuccess) 성공적인 인증을 기록하고, ID 토큰 및 클레임을 검색하고, CoroutineScope를 사용하여 액세스 토큰을 비동기식으로 업데이트하고, 새 액세스 토큰으로 UI를 업데이트합니다. 코드는 authenticationResult에서 ID 토큰을 검색하여 기록합니다. 토큰의 클레임에는 이름, 이메일, 기타 프로필 정보 등 사용자에 대한 정보가 포함됩니다. authenticationResult.account.claims에 액세스하여 현재 계정과 관련된 소유권 클레임을 검색할 수 있습니다.

    인증 오류(onError)가 있는 경우 오류를 기록하고, 액세스 토큰을 지우고, 오류 메시지로 UI를 업데이트하고, MsalClientExceptionMsalServiceException에 대한 보다 구체적인 처리를 제공합니다. 사용자가 인증(onCancel)을 취소하면 취소가 기록됩니다.

    import 문을 포함했는지 확인합니다. Android Studio에는 import 문이 자동으로 포함되어야 합니다.

  2. 사용자가 자동으로 로그인하도록 하려면 다음 코드를 사용합니다.

        private fun acquireTokenSilently() {
        binding.txtLog.text = ""
    
        if (account == null) {
            Toast.makeText(this, "No account available", Toast.LENGTH_SHORT).show()
            return
        }
    
        /* Extracts a scope array from text, i.e. from "User.Read User.ReadWrite" to ["user.read", "user.readwrite"] */
        val scopes = scopes.lowercase().split(" ")
        val parameters = AcquireTokenSilentParameters.Builder()
            .forAccount(account)
            .fromAuthority(account!!.authority)
            .withScopes(scopes)
            .forceRefresh(false)
            .withCallback(getAuthSilentCallback())
            .build()
    
        authClient.acquireTokenSilentAsync(parameters)
    }
    

    코드는 자동으로 토큰 획득 프로세스를 시작합니다. 먼저 텍스트 로그를 지웁니다. 그런 다음 사용 가능한 계정이 있는지 확인합니다. 계정이 없으면 이를 알리는 알림 메시지를 표시하고 종료됩니다. 다음으로, 텍스트 입력에서 범위를 추출하고 이를 소문자로 변환한 후 배열로 분할합니다.

    이러한 범위를 사용하여 자동으로 토큰을 획득하기 위한 매개 변수를 구성하고 계정, 권한, 범위 및 콜백을 지정합니다. 마지막으로 구성된 매개 변수를 사용하여 인증 클라이언트에서 acquireTokenSilentAsync()를 비동기식으로 트리거하여 자동 토큰 획득 프로세스를 시작합니다.

    콜백을 지정하는 코드에서는 getAuthSilentCallback()이라는 함수를 사용합니다. 함수에는 다음 코드가 있어야 합니다.

    private fun getAuthSilentCallback(): SilentAuthenticationCallback {
        return object : SilentAuthenticationCallback {
            override fun onSuccess(authenticationResult: IAuthenticationResult?) {
                Log.d(TAG, "Successfully authenticated")
    
                /* Display Access Token */
                accessToken = authenticationResult?.accessToken
                binding.txtLog.text = getString(R.string.log_token_silent) + accessToken
            }
    
            override fun onError(exception: MsalException?) {
                /* Failed to acquireToken */
                Log.d(TAG, "Authentication failed: $exception")
    
                accessToken = null
                binding.txtLog.text = getString(R.string.exception_authentication) + exception
    
                when (exception) {
                    is MsalClientException -> {
                        /* Exception inside MSAL, more info inside MsalError.java */
                    }
                    is MsalServiceException -> {
                        /* Exception when communicating with the STS, likely config issue */
                    }
                    is MsalUiRequiredException -> {
                        /* Tokens expired or no session, retry with interactive */
                    }
                }
            }
    
        }
    }
    

    코드는 자동 인증을 위한 콜백을 정의합니다. 두 메서드를 재정의하여 SilentAuthenticationCallback 인터페이스를 구현합니다. onSuccess 메서드에서는 성공적인 인증을 기록하고 액세스 토큰을 표시합니다.

    onError 메서드에서는 인증 실패를 기록하고, MsalClientExceptionMsalServiceException과 같은 다양한 형식의 예외를 처리하며, 필요한 경우 대화형 인증을 사용한 다시 시도를 제안합니다.

    import 문을 포함했는지 확인합니다. Android Studio에는 import 문이 자동으로 포함되어야 합니다.

로그아웃

Android용 MSAL을 사용하여 Android(Kotlin) 앱에서 사용자가 로그아웃하도록 하려면 다음 코드를 사용합니다.

private fun removeAccount() {
    binding.userName.text = ""
    binding.txtLog.text = ""

    authClient.signOut(signOutCallback())
}

코드는 애플리케이션에서 계정을 제거합니다. 표시된 사용자 이름과 텍스트 로그를 지웁니다. 그런 다음 인증 클라이언트를 사용하여 로그아웃 프로세스를 트리거하고 로그아웃 작업 완료를 처리하기 위한 로그아웃 콜백을 지정합니다.

콜백을 지정하는 코드에서는 signOutCallback()이라는 함수를 사용합니다. 함수에는 다음 코드가 있어야 합니다.

private fun signOutCallback(): ISingleAccountPublicClientApplication.SignOutCallback {
    return object : ISingleAccountPublicClientApplication.SignOutCallback {
        override fun onSignOut() {
            account = null
            updateUI(account)
        }

        override fun onError(exception: MsalException) {
            binding.txtLog.text = getString(R.string.exception_remove_account) + exception
        }
    }
}

코드는 공용 클라이언트 애플리케이션의 단일 계정에 대한 로그아웃 콜백을 정의합니다. 두 메서드를 재정의하여 ISingleAccountPublicClientApplication.SignOutCallback 인터페이스를 구현합니다.

onSignOut 메서드에서는 현재 계정을 무효화하고 이에 따라 사용자 인터페이스를 업데이트합니다. onError 메서드에서는 로그아웃 프로세스 중에 발생하는 모든 오류를 기록하고 해당 예외 메시지로 텍스트 로그를 업데이트합니다.

import 문을 포함했는지 확인합니다. Android Studio에는 import 문이 자동으로 포함되어야 합니다.

다음 단계

자습서: Android(Kotlin) 앱에서 보호된 웹 API를 호출합니다.