Итак, сегодня мы продолжаем разбираться с различными механизмами авторизации пользователей в приложениях на Xamarin. После знакомства с SDK от Facebook и ВКонтакте (здесь и здесь), можем перейти к одному из самых популярных (на текущий момент) механизмов внешней авторизации пользователей — OAuth. Большинство популярных сервисов вроде Twitter, Microsoft Live, Github и так далее, предоставляют своим пользователям возможность входа в сторонние приложения с помощью одного привычного аккаунта. Научившись работать с OAuth вы легко сможете подключать все эти сервисы и забирать из них информацию о пользователе.
Предполагается, что вы уже знакомы с тем, как работает OAuth, а если нет — рекомендуем вот эту хорошую статью на Хабре. Если коротко, то при авторизации OAuth пользователь перенаправляется с одной веб-страницы на другую (обычно 2-3 шага) до тех пор, пока не перейдет на конечный URL. Этот финальный переход и будет отловлен в приложении (если писать логику самому) на уровне WebView, а нужные данные (token и срок его валидности) будут указаны прямо в URL.
Небольшой список популярных сервисов, которые предоставляют возможность авторизации пользователей по OAuth: Одноклассники, Mail.ru, Dropbox, Foursquare, GitHub, Instagram, LinkedIn, Microsoft, Slack, SoundCloud, Visual Studio Online, Trello.
Xamarin.Auth
Для того, чтобы работать с OAuth в Xamarin мы остановимся на простой и удобной библиотеке Xamarin.Auth, которая развивается уже не первый год и имеет все необходимые для нас механизмы:
- Отображение браузера со страницами авторизации
- Управление потоком редиректов и процессом авторизации
- Получение нужных данных
- Предоставление механизмов для дополнительных запросов к сервису, например для получения информации о пользователе
Также Xamarin.Auth поддерживает возможность хранения учетных данных пользователя в защищенном хранилище. В общем, зрелый и качественный компонент с необходимой функциональностью.
Рекомендуем устанавливать Xamarin.Auth из Nuget, так как версия в Xamarin Components уже давно устарела и не обновляется.
Напомню, что мы уже ранее рассказывали про авторизацию с помощью SDK от Facebook и ВКонтакте. В нашем примере мы вынесли всю логику авторизации в платформенные проекты, оставив в PCL только интерфейсы. Для OAuth мы пойдем тем же путем, несмотря на поддержку PCL в самом Xamarin.Auth.
Помимо Xamarin.Auth можем также порекомендовать библиотеку Xamarin.Forms.OAuth от Bruno Bernardo. Даже если вы используете классический Xamarin, в исходных кодах этого проекта можно найти множество готовых конфигураций для различных сервисов.
Мы же в качестве примера работы OAuth подключим авторизацию с помощью Microsoft. Первым делом создадим приложение на сайте https://apps.dev.microsoft.com и получим там Client ID (ИД клиента или приложения).
Подключаем авторизацию в PCL
На уровне PCL все как обычно — делаем простой интерфейс IOAuthService для платформенного сервиса, никаких новых зависимостей в проект не добавляем.
public interface IOAuthService
{
Task<LoginResult> Login();
void Logout();
}
Ну и, конечно же, будет необходимо добавить обращение к методам DependencyService.Get<IOAuthService>().Login()
и DependencyService.Get<IOAuthService>().Logout()
внутри нашей страницы авторизации.
Также нет проблем добавить поддержку нескольких OAuth-сервисов. Для этого можно добавить в методы Login()
и Logout()
аргумент providerName
(тип string
, int
или enum
) и в зависимости от его значения выбирать поставщика услуг.
Реализация платформенной части
Как уже отмечалось ранее, необходимо добавить библиотеки Xamarin.Auth из Nuget в каждый платформенный проект, в нашем случае — iOS и Android. Дальше пишем нашу реализацию IOAuthService
для каждой платформы и регистрируем ее в качестве Dependency
.
Теперь нам достаточно создать экземпляр класса OAuth2Authenticator
с нужными параметрами:
var auth = new OAuth2Authenticator
(
clientId: "ВАШ_CLIENT_ID",
scope: "wl.basic, wl.emails, wl.photos",
authorizeUrl: new Uri("https://login.live.com/oauth20_authorize.srf"),
redirectUrl: new Uri("https://login.live.com/oauth20_desktop.srf"),
clientSecret: null,
accessTokenUrl: new Uri("https://login.live.com/oauth20_token.srf")
)
{
AllowCancel = true
};
Теперь повесим обработчик завершения авторизации:
auth.Completed += AuthOnCompleted;
Всё, можно показать модальное окно со встроенным веб-браузером для авторизации, получаемое через метод auth.GetUI()
. На iOS это можно сделать примерно так:
UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewController(auth.GetUI(), true, null);
На Android при использовании Xamarin.Forms код может получится следующим:
Forms.Context.StartActivity(auth.GetUI(Forms.Context));
После успешной авторизации вызовется наш метод AuthOnCompleted()
, и для iOS будет необходимо скрыть модальное окно с браузером (на Android само скроется):
UIApplication.SharedApplication.KeyWindow.RootViewController.DismissViewController(true, null);
Теперь можно получать нужные данные (access_token
и время его жизни в секундах — expires_in
)
var token = authCompletedArgs.Account.Properties["access_token"];
var expireIn = Convert.ToInt32(authCompletedArgs.Account.Properties["expires_in"]);
var expireAt = DateTimeOffset.Now.AddSeconds(expireIn);
И нам остался последний шаг — получить расширенную информацию из профиля пользователя, включая email и ссылку на аватарку. Для этого в Xamarin.Auth есть специальный класс OAuth2Request
с помощью которого удобно делать подобные запросы.
var request = new OAuth2Request("GET", new Uri("https://apis.live.net/v5.0/me"), null, account);
var response = await request.GetResponseAsync();
Теперь нам приходит JSON с данными пользователя, и мы можем их сохранить и отобразить в приложении.
if (response.StatusCode == HttpStatusCode.OK)
{
var userJson = response.GetResponseText();
var jobject = JObject.Parse(userJson);
result.LoginState = LoginState.Success;
result.Email = jobject["emails"]?["preferred"].ToString();
result.FirstName = jobject["first_name"]?.ToString();
result.LastName = jobject["last_name"]?.ToString();
result.ImageUrl = jobject["picture"]?["data"]?["url"]?.ToString();
var userId = jobject["id"]?.ToString();
result.UserId = userId;
result.ImageUrl = $"https://apis.live.net/v5.0/{userId}/picture";
}
Как видим, ничего сложного нет. Вопрос в том, чтобы правильно прописать URL для процесса авторизации. Ну и помнить, что поле expires_in
содержит время в секундах (это вызывает частые вопросы).
В реальных проектах также рекомендуем назначить обработчик ошибок на событие auth.Error
, чтобы ни одна проблема не осталась без решения.
Заключение
Сегодня мы завершили рассмотрение всех популярных способов авторизации пользователей и получения базовой информации о них через внешние сервисы. Описанные механизмы подходят как для Xamarin.Forms, так и для классического Xamarin iOS/Android. Полные исходные коды проекта со всеми примерами можно найти в нашем репозитории:
https://bitbucket.org/binwell/login
Задавайте ваши вопросы в комментариях к статье и оставайтесь на связи!
Об авторе
Вячеслав Черников — руководитель отдела разработки компании Binwell, Microsoft MVP и Xamarin Certified Developer. В прошлом — один из Nokia Champion и Qt Certified Specialist, в настоящее время — специалист по платформам Xamarin и Azure. В сферу mobile пришел в 2005 году, с 2008 года занимается разработкой мобильных приложений: начинал с Symbian, Maemo, Meego, Windows Mobile, потом перешел на iOS, Android и Windows Phone. Статьи Вячеслава вы также можете прочитать в блоге на Medium.
Другие статьи автора:
- Автоматизируем неавтоматизируемое, или про Xamarin в реальных проектах
- Деплоим мобильный софт с помощью devops-конвейера Microsoft
- DevOps на службе человека
- Удобный REST для Xamarin-приложений
- Быстрое создание MVP (minimum viable product) на базе Microsoft Azure и Xamarin.Forms
- Готовим Xamarin.Forms: настройка окружения и первые шаги
- Повышаем эффективность работы в Xamarin.Forms
- Работаем с состояниями экранов в Xamarin.Forms
- Подключаем Facebook SDK для Xamarin.Forms
- Подключаем ВКонтакте SDK для Xamarin.Forms
Автор: Microsoft