Поделиться через


Включение аутентификации в собственном приложении Android с помощью Azure Active Directory B2C

В этой статье показано, как добавить аутентификацию Azure Active Directory B2C (Azure AD B2C) в собственное мобильное приложение Android.

Используйте эту статью вместе с разделом Настройка проверки подлинности на примере приложения Android с помощью Azure AD B2C, заменив приложение Android из примера своим собственным приложением Android. После выполнения инструкций, описанных в этой статье, ваше приложение будет принимать запросы на вход через Azure AD B2C.

Необходимые компоненты

Ознакомьтесь с предварительными требованиями и инструкциями по интеграции в разделе Настройка проверки подлинности на примере приложения Android с помощью Azure AD B2C.

Создание проекта приложения Android

Если у вас еще нет приложения Android, настройте новый проект следующим образом.

  1. В Android Studio щелкните Start a new Android Studio project (Создать проект Android Studio).
  2. Выберите Базовое действие и нажмите Далее.
  3. Присвойте имя приложению.
  4. Сохраните имя пакета. Позже вы укажете его на портале Azure.
  5. Измените язык с Kotlin на Java.
  6. Присвойте параметру Минимальный уровень API задайте API 19 или выше и затем выберите Готово.
  7. В представлении проекта в раскрывающемся списке выберите Проект, чтобы отобразить исходные и другие файлы проекта, откройте app/build.gradle и задайте для параметра targetSdkVersion значение 28.

Шаг 1. Установка зависимостей

В окне проекта Android Studio перейдите к app>build.gradle и добавьте следующее.

apply plugin: 'com.android.application'

allprojects {
    repositories {
    mavenCentral()
    google()
    mavenLocal()
    maven {
        url 'https://pkgs.dev.azure.com/MicrosoftDeviceSDK/DuoSDK-Public/_packaging/Duo-SDK-Feed/maven/v1'
    }
    maven {
        name "vsts-maven-adal-android"
        url "https://identitydivision.pkgs.visualstudio.com/_packaging/AndroidADAL/maven/v1"
        credentials {
            username System.getenv("ENV_VSTS_MVN_ANDROIDADAL_USERNAME") != null ? System.getenv("ENV_VSTS_MVN_ANDROIDADAL_USERNAME") : project.findProperty("vstsUsername")
            password System.getenv("ENV_VSTS_MVN_ANDROIDADAL_ACCESSTOKEN") != null ? System.getenv("ENV_VSTS_MVN_ANDROIDADAL_ACCESSTOKEN") : project.findProperty("vstsMavenAccessToken")
        }
    }
    jcenter()
    }
}
dependencies{
    implementation 'com.microsoft.identity.client:msal:2.+'
    }
packagingOptions{
    exclude("META-INF/jersey-module-version")
}

Шаг 2. Добавление компонентов проверки подлинности

Пример кода состоит из следующих компонентов. Добавьте эти компоненты из примера приложения Android в свое собственное приложение.

Компонент Тип Оригинал Description
B2CUser Класс Kotlin Java Представляет пользователя B2C. Этот класс позволяет пользователям входить в систему с несколькими политиками.
B2CModeFragment Класс фрагмента Kotlin Java Фрагмент представляет собой модульную часть пользовательского интерфейса входа в Azure AD B2C в рамках вашего основного действия. Этот фрагмент содержит большую часть кода проверки подлинности.
fragment_b2c_mode.xml Макет фрагмента Kotlin Java Определяет структуру пользовательского интерфейса для компонента фрагмента B2CModeFragment.
B2CConfiguration Класс Kotlin Java Файл конфигурации содержит сведения о вашем поставщике удостоверений Azure AD B2C. Мобильное приложение использует эти сведения для установления отношений доверия с Azure AD B2C, выполнения входа и выхода пользователя, получения маркеров и их проверки. Дополнительные параметры конфигурации описаны в файле auth_config_b2c.json.
auth_config_b2c.json Файл JSON Kotlin Java Файл конфигурации содержит сведения о вашем поставщике удостоверений Azure AD B2C. Мобильное приложение использует эти сведения для установления отношений доверия с Azure AD B2C, выполнения входа и выхода пользователя, получения маркеров и их проверки. Дополнительные параметры конфигурации описаны в классе B2CConfiguration.

Шаг 3. Настройка приложения Android

Добавив компоненты проверки подлинности, настройте приложение Android с помощью параметров Azure AD B2C. Параметры поставщика удостоверений Azure AD B2C настроены в файле auth_config_b2c.json и классе B2CConfiguration.

Инструкции см. в разделе Настройка примера мобильного приложения.

Шаг 4. Настройка URI перенаправления

Выполните настройку местоположения, где приложение ожидает передачи данных при ответе токена Azure AD B2C.

  1. Создайте хэш подписи для новой разработки. Он будет меняться для каждой среды разработки.

    Для Windows:

    keytool -exportcert -alias androiddebugkey -keystore %HOMEPATH%\.android\debug.keystore | openssl sha1 -binary | openssl base64
    

    Для iOS:

    keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore | openssl sha1 -binary | openssl base64
    

    Для рабочей среды используйте следующую команду:

    keytool -exportcert -alias SIGNATURE_ALIAS -keystore PATH_TO_KEYSTORE | openssl sha1 -binary | openssl base64
    

    Для получения дополнительных сведений о подписи ваших приложений см. статью Подписывание приложения Android.

  2. Выберите файл app>src>main>AndroidManifest.xml, затем добавьте следующее действие BrowserTabActivity в код приложения.

    <!--Intent filter to capture System Browser or Authenticator calling back to our app after sign-in-->
    <activity
        android:name="com.microsoft.identity.client.BrowserTabActivity">
        <intent-filter>
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT" />
            <category android:name="android.intent.category.BROWSABLE" />
            <data android:scheme="msauth"
                android:host="Package_Name"
                android:path="/Signature_Hash" />
        </intent-filter>
    </activity>
    
  3. Замените Signature_Hash на хэш, который был сгенерирован.

  4. Замените Package_Name на имя пакета Android.

Чтобы обновить регистрацию мобильного приложения с помощью URI перенаправления вашего приложения, выполните следующее.

  1. Войдите на портал Azure.
  2. Если у вас есть доступ к нескольким клиентам, щелкните значок "Параметры " в верхнем меню, чтобы переключиться на клиент Azure AD B2C из меню каталогов и подписок .
  3. Найдите и выберите Azure AD B2C.
  4. Выберите Регистрация приложений, а затем выберите приложение, которые вы зарегистрировали при выполнении действия Шаг 2.3. Регистрация мобильного приложения.
  5. Выберите Проверка подлинности.
  6. В Android выберите Добавить URI.
  7. Введите Имя пакета и Хэш подписи.
  8. Выберите Сохранить.

Ваш URI перенаправления и действие BrowserTabActivity должны выглядеть приблизительно так, как показано в примере ниже:

URL-адрес перенаправления для примера Android выглядит следующим образом.

msauth://com.azuresamples.msalandroidkotlinapp/1wIqXSqBj7w%2Bh11ZifsnqwgyKrY%3D

Фильтр намерений использует тот же шаблон, который показан в следующем фрагменте кода XML.

<activity android:name="com.microsoft.identity.client.BrowserTabActivity">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data
            android:host="com.azuresamples.msalandroidkotlinapp"
            android:path="/1wIqXSqBj7w+h11ZifsnqwgyKrY="
            android:scheme="msauth" />
    </intent-filter>
</activity>

Шаг 5. Настройка составляющих блоков кода

В этом разделе описаны базовые блоки кода, которые обеспечивают проверку подлинности для приложения Android. В следующей таблице перечислены методы B2CModeFragment и способы настройки вашего кода.

Шаг 5.1. Создание экземпляра общедоступного клиентского приложения

Общедоступные клиентские приложения не считаются безопасными для хранения секретов приложения и не содержат секреты клиента. В onCreate или onCreateView создайте экземпляр MSAL с помощью общедоступного объекта клиентского приложения с несколькими учетными записями.

Класс MultipleAccountPublicClientApplication используется для создания приложений на основе MSAL, которые позволяют войти в несколько учетных записей одновременно. Класс разрешает вход с несколькими пользовательскими потоками или пользовательскими политиками Azure AD B2C. Например, пользователи входят с помощью пользовательского потока регистрации или входа, а позже запускают пользовательский поток редактирование профиля.

Следующий фрагмент кода демонстрирует инициализацию библиотеки MSAL с помощью файла JSON конфигурации auth_config_b2c.json.

PublicClientApplication.createMultipleAccountPublicClientApplication(context!!,
    R.raw.auth_config_b2c,
    object : IMultipleAccountApplicationCreatedListener {
        override fun onCreated(application: IMultipleAccountPublicClientApplication) {
            // Set the MultipleAccountPublicClientApplication to the class member b2cApp
            b2cApp = application
            // Load the account (if there is any)
            loadAccounts()
        }

        override fun onError(exception: MsalException) {
            // Error handling
            displayError(exception)
        }
    })

Шаг 5.2. Загрузка учетных записей

Когда приложение выходит на передний план, оно загружает существующую учетную запись, чтобы определить, вошел ли пользователь в систему. Используйте этот метод для обновления пользовательского интерфейса с указанием состояния проверки подлинности. Например, можно включить или выключить кнопку выхода из системы.

В следующем фрагменте кода показано, как загрузить учетные записи.

private fun loadAccounts() {
    if (b2cApp == null) {
        return
    }
    b2cApp!!.getAccounts(object : LoadAccountsCallback {
        override fun onTaskCompleted(result: List<IAccount>) {
            users = B2CUser.getB2CUsersFromAccountList(result)
            updateUI(users)
        }
    
        override fun onError(exception: MsalException) {
            displayError(exception)
        }
    })
    }

Шаг 5.3. Запуск интерактивного запроса на авторизацию

Интерактивный запрос авторизации — это поток, в котором пользователю предлагается зарегистрироваться или войти в систему. Метод initializeUI настраивает событие щелчка runUserFlowButton. Когда пользователи нажимают кнопку Выполнить пользовательский поток, приложение переносит их в Azure AD B2C, чтобы завершить поток входа.

Метод runUserFlowButton.setOnClickListener подготавливает объект AcquireTokenParameters с использованием соответствующих данных о запросе авторизации. Затем метод acquireToken предлагает пользователям завершить процесс регистрации или входа.

Следующий фрагмент кода показывает, как запустить интерактивный запрос авторизации.

val parameters = AcquireTokenParameters.Builder()
        .startAuthorizationFromActivity(activity)
        .fromAuthority(getAuthorityFromPolicyName(policy_list.getSelectedItem().toString()))
        .withScopes(B2CConfiguration.scopes)
        .withPrompt(Prompt.LOGIN)
        .withCallback(authInteractiveCallback)
        .build()

b2cApp!!.acquireToken(parameters)

Шаг 5.4. Обратный вызов интерактивного запроса проверки подлинности

После того как пользователи завершат процесс авторизации (успешно или безуспешно), результат возвращается в метод обратного вызова getAuthInteractiveCallback().

Метод обратного вызова передает объект AuthenticationResult или сообщение об ошибке в объект MsalException. Используйте этот метод для следующих целей:

  • обновление пользовательского интерфейса мобильного приложения путем указания сведений после завершения входа;
  • перезагрузка объекта учетных записей;
  • вызов службы веб-API с помощью маркера доступа;
  • обработка ошибок проверки подлинности.

Следующий фрагмент кода демонстрирует, как использовать интерактивный обратный вызов проверки подлинности.

private val authInteractiveCallback: AuthenticationCallback
    private get() = 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")

            /* display result info */
            displayResult(authenticationResult)

            /* Reload account asynchronously to get the up-to-date list. */
            loadAccounts()
        }

        override fun onError(exception: MsalException) {
            val B2C_PASSWORD_CHANGE = "AADB2C90118"
            if (exception.message!!.contains(B2C_PASSWORD_CHANGE)) {
                txt_log!!.text = """
                    Users click the 'Forgot Password' link in a sign-up or sign-in user flow.
                    Your application needs to handle this error code by running a specific user flow that resets the password.
                    """.trimIndent()
                return
            }

            /* Failed to acquireToken */Log.d(TAG, "Authentication failed: $exception")
            displayError(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.")
        }
    }

Шаг 6. Вызов веб-API

Для вызова веб-API авторизации на основе токена приложению требуется действительный маркер доступа. Приложение выполняет следующие действия:

  1. Получает маркер доступа с необходимыми разрешениями (областями) для конечной точки веб-API.
  2. Передает токен доступа как токен-носитель в заголовке авторизации HTTP-запроса, используя этот формат.
Authorization: Bearer <access-token>

Когда пользователи выполняют интерактивный вход, приложение получает маркер доступа в методе обратного вызова getAuthInteractiveCallback. Для последующих вызовов веб-API используйте процедуру получения токена в автоматическом режиме, как описано в этом разделе.

Перед вызовом веб-API вызовите метод acquireTokenSilentAsync с соответствующими областями для конечной точки веб-API. Библиотека MSAL выполняет следующие действия.

  1. Пытается получить маркер доступа с запрошенными областями из кэша маркеров. Если маркер имеется, возвращается маркер.
  2. Если маркер отсутствует в кэше маркеров, MSAL пытается использовать маркер обновления для получения нового маркера.
  3. Если маркер обновления не существует или срок его действия истек, возвращается исключение. Рекомендуется предложить пользователю выполнить интерактивный вход.

В следующем фрагменте кода показано, как получить маркер доступа:

Событие нажатия кнопки acquireTokenSilentButton получает маркер доступа с указанными областями.

btn_acquireTokenSilently.setOnClickListener(View.OnClickListener {
    if (b2cApp == null) {
        return@OnClickListener
    }
    val selectedUser = users!![user_list.getSelectedItemPosition()]
    selectedUser.acquireTokenSilentAsync(b2cApp!!,
            policy_list.getSelectedItem().toString(),
            B2CConfiguration.scopes,
            authSilentCallback)
})

Метод обратного вызова authSilentCallback возвращает маркер доступа и вызывает веб-API:

private val authSilentCallback: SilentAuthenticationCallback
    private get() = object : SilentAuthenticationCallback {
        override fun onSuccess(authenticationResult: IAuthenticationResult) {
            Log.d(TAG, "Successfully authenticated")

            /* Call your web API here*/
            callWebAPI(authenticationResult)
        }

        override fun onError(exception: MsalException) {
            /* Failed to acquireToken */
            Log.d(TAG, "Authentication failed: $exception")
            displayError(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 */
            } else if (exception is MsalUiRequiredException) {
                /* Tokens expired or no session, retry with interactive */
            }
        }
    }

Следующий пример демонстрирует, как вызвать защищенный веб-API с помощью маркера носителя:

@Throws(java.lang.Exception::class)
private fun callWebAPI(authenticationResult: IAuthenticationResult) {
    val accessToken = authenticationResult.accessToken
    val thread = Thread {
        try {
            val url = URL("https://your-app-service.azurewebsites.net/helo")
            val conn = url.openConnection() as HttpsURLConnection
            conn.setRequestProperty("Accept", "application/json")
            
            // Set the bearer token
            conn.setRequestProperty("Authorization", "Bearer $accessToken")
            if (conn.responseCode == HttpURLConnection.HTTP_OK) {
                val br = BufferedReader(InputStreamReader(conn.inputStream))
                var strCurrentLine: String?
                while (br.readLine().also { strCurrentLine = it } != null) {
                    Log.d(TAG, strCurrentLine)
                }
            }
            conn.disconnect()
        } catch (e: IOException) {
            e.printStackTrace()
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }
    thread.start()
}

Добавление разрешения на выполнение сетевых операций

Чтобы выполнять сетевые операции в приложении, добавьте в манифест следующее разрешение. Дополнительные сведения см. в разделе Подключение к сети.

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

Следующие шаги

Вы узнаете, как выполнять следующие задачи: