Использование поставщиков OAuth с MVC 4

; автор — Том ФитцМакен (Tom FitzMacken)

В этом руководстве показано, как создать веб-приложение ASP.NET MVC 4, которое позволяет пользователям входить с учетными данными внешнего поставщика, например Facebook, Twitter, Майкрософт или Google, а затем интегрировать некоторые функции этих поставщиков в веб-приложение. Для простоты в этом руководстве основное внимание уделяется работе с учетными данными из Facebook.

Сведения об использовании внешних учетных данных в веб-приложении ASP.NET MVC 5 см. в статье Создание ASP.NET приложения MVC 5 с помощью Facebook и Google OAuth2 и входа OpenID.

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

Содержание задачи

В этом руководстве есть две main цели:

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

Хотя в примерах в этом руководстве основное внимание уделяется использованию Facebook в качестве поставщика проверки подлинности, вы можете изменить код, чтобы использовать любой из поставщиков. Шаги по реализации любого поставщика очень похожи на шаги, которые вы увидите в этом руководстве. Вы заметите существенные различия только при выполнении прямых вызовов набора API поставщика.

Предварительные требования

либо

Кроме того, в этом разделе предполагается, что у вас есть базовые знания о ASP.NET MVC и Visual Studio. Общие сведения о ASP.NET MVC 4 см. в статье Введение в ASP.NET MVC 4.

Создание проекта

В Visual Studio создайте новое ASP.NET веб-приложение MVC 4 и назовите его OAuthMVC. Вы можете выбрать платформа .NET Framework 4.5 или 4.

создание проекта

В окне Создать проект ASP.NET MVC 4 выберите Интернет-приложение и оставьте Razor в качестве обработчика представлений.

Выберите Интернет-приложение

Включение поставщика

При создании веб-приложения MVC 4 с помощью шаблона интернет-приложения проект создается с файлом AuthConfig.cs в папке App_Start.

Файл AuthConfig

Файл AuthConfig содержит код для регистрации клиентов для внешних поставщиков проверки подлинности. По умолчанию этот код закомментирован, поэтому ни один из внешних поставщиков не включен.

public static class AuthConfig
{
    public static void RegisterAuth()
    {
        // To let users of this site log in using their accounts from other sites such as Microsoft, Facebook, and Twitter,
        // you must update this site. For more information visit https://go.microsoft.com/fwlink/?LinkID=252166

        //OAuthWebSecurity.RegisterMicrosoftClient(
        //    clientId: "",
        //    clientSecret: "");

        //OAuthWebSecurity.RegisterTwitterClient(
        //    consumerKey: "",
        //    consumerSecret: "");

        //OAuthWebSecurity.RegisterFacebookClient(
        //    appId: "",
        //    appSecret: "");

        //OAuthWebSecurity.RegisterGoogleClient();
    }
}

Этот код необходимо раскомментировать, чтобы использовать внешний клиент проверки подлинности. Раскомментируйте только поставщиков, которые вы хотите включить на свой сайт. В этом руководстве вы включите только учетные данные Facebook.

public static class AuthConfig
{
    public static void RegisterAuth()
    {
        //OAuthWebSecurity.RegisterMicrosoftClient(
        //    clientId: "",
        //    clientSecret: "");

        //OAuthWebSecurity.RegisterTwitterClient(
        //    consumerKey: "",
        //    consumerSecret: "");

        OAuthWebSecurity.RegisterFacebookClient(
            appId: "",
            appSecret: "");

        //OAuthWebSecurity.RegisterGoogleClient();        
    }
}

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

Регистрация во внешнем поставщике

Для проверки подлинности пользователей с учетными данными внешнего поставщика необходимо зарегистрировать веб-сайт в поставщике. При регистрации сайта вы получите параметры (например, ключ или идентификатор и секрет), которые будут включены при регистрации клиента. У вас должна быть учетная запись с поставщиками, которые вы хотите использовать.

В этом руководстве не показаны все действия, которые необходимо выполнить для регистрации в этих поставщиках. Как правило, эти шаги не сложны. Чтобы успешно зарегистрировать сайт, следуйте инструкциям на этих сайтах. Чтобы приступить к регистрации сайта, ознакомьтесь с сайтом разработчика для:

При регистрации сайта в Facebook можно указать localhost для домена сайта и "http://localhost/" URL-адреса, как показано на рисунке ниже. Использование localhost работает с большинством поставщиков, но в настоящее время не работает с поставщиком Майкрософт. Для поставщика Майкрософт необходимо указать допустимый URL-адрес веб-сайта.

Регистрация сайта

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

Создание тестовых пользователей

Если вы не против использования существующей учетной записи Facebook для тестирования сайта, этот раздел можно пропустить.

Вы можете легко создать тестовых пользователей для своего приложения на странице управления приложениями Facebook. Эти тестовые учетные записи можно использовать для входа на сайт. Для создания тестовых пользователей щелкните ссылку Роли в левой области навигации и щелкните ссылку Создать .

создание тестовых пользователей

Сайт Facebook автоматически создает количество запрашиваемых тестовых учетных записей.

Добавление идентификатора приложения и секрета из поставщика

Теперь, когда вы получили идентификатор и секрет от Facebook, вернитесь к файлу AuthConfig и добавьте их в качестве значений параметров. Приведенные ниже значения не являются реальными.

public static class AuthConfig
{
    public static void RegisterAuth()
    {
        //OAuthWebSecurity.RegisterMicrosoftClient(
        //    clientId: "",
        //    clientSecret: "");

        //OAuthWebSecurity.RegisterTwitterClient(
        //    consumerKey: "",
        //    consumerSecret: "");

        //OAuthWebSecurity.RegisterFacebookClient(
        //    appId: "",
        //    appSecret: "");

        //OAuthWebSecurity.RegisterGoogleClient();
    }
}

Вход с внешними учетными данными

Это все, что вам нужно сделать, чтобы включить внешние учетные данные на сайте. Запустите приложение и щелкните ссылку для входа в правом верхнем углу. Шаблон автоматически распознает, что вы зарегистрировали Facebook в качестве поставщика, и включает в себя кнопку для поставщика. При регистрации нескольких поставщиков автоматически включается кнопка для каждого из них.

внешнее имя входа

В этом руководстве не рассматривается настройка кнопок входа для внешних поставщиков. Эти сведения см. в статье Настройка пользовательского интерфейса входа при использовании OAuth/OpenID.

Нажмите кнопку Facebook, чтобы войти с учетными данными Facebook. При выборе одного из внешних поставщиков вы будете перенаправлены на этот сайт и ей будет предложено войти в систему.

На следующем рисунке показан экран входа для Facebook. В нем отмечается, что вы используете свою учетную запись Facebook для входа на сайт с именем oauthmvcexample.

Проверка подлинности Facebook

После входа с учетными данными Facebook страница сообщает пользователю, что сайт будет иметь доступ к основной информации.

запрос разрешения

После нажатия кнопки Перейти к приложению пользователь должен зарегистрироваться на сайте. На следующем рисунке показана страница регистрации после входа пользователя с учетными данными Facebook. Имя пользователя обычно заполняется именем поставщика.

Снимок экрана: страница регистрации, где можно связать учетную запись Facebook с этим приложением.

Нажмите кнопку Зарегистрировать , чтобы завершить регистрацию. Закройте браузер.

Вы увидите, что новая учетная запись добавлена в базу данных. В Обозреватель сервера откройте базу данных DefaultConnection и папку Таблицы.

таблицы базы данных

Щелкните правой кнопкой мыши таблицу UserProfile и выберите Показать данные таблицы.

показать данные

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

Если вы хотите включить только внешнюю проверку подлинности, все готово. Однако вы можете дополнительно интегрировать сведения от поставщика в процесс регистрации нового пользователя, как показано в следующих разделах.

Создание моделей для получения дополнительных сведений о пользователе

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

Вы будете использовать Code First Migrations для добавления таблицы для хранения дополнительных сведений о пользователе. Вы добавляете таблицу в существующую базу данных, поэтому сначала необходимо создать snapshot текущей базы данных. Создав snapshot текущей базы данных, можно позже создать миграцию, содержащую только новую таблицу. Чтобы создать snapshot текущей базы данных, выполните следующие действия.

  1. Открытие консоли диспетчера пакетов
  2. Выполните команду enable-migrations.
  3. Выполните команду add-migration initial –IgnoreChanges.
  4. Выполнение команды update-database

Теперь вы добавите новые свойства. В папке Models откройте файл AccountModels.cs и найдите класс RegisterExternalLoginModel. Класс RegisterExternalLoginModel содержит значения, возвращаемые поставщиком проверки подлинности. Добавьте свойства с именами FullName и Link, как показано ниже.

public class RegisterExternalLoginModel
{
    [Required]
    [Display(Name = "User name")]
    public string UserName { get; set; }

    public string ExternalLoginData { get; set; }

    [Display(Name = "Full name")]
    public string FullName { get; set; }

    [Display(Name = "Personal page link")]
    public string Link { get; set; }
}

Также в AccountModels.cs добавьте новый класс с именем ExtraUserInformation. Этот класс представляет новую таблицу, которая будет создана в базе данных.

[Table("ExtraUserInformation")]
public class ExternalUserInformation
{
    public int Id { get; set; }
    public int UserId { get; set; }
    public string FullName { get; set; }
    public string Link { get; set; }
    public bool? Verified { get; set; }
}

В классе UsersContext добавьте выделенный ниже код, чтобы создать свойство DbSet для нового класса.

public class UsersContext : DbContext
{
    public UsersContext()
        : base("DefaultConnection")
    {
    }

    public DbSet<UserProfile> UserProfiles { get; set; }
    public DbSet<ExternalUserInformation> ExternalUsers { get; set; }
}

Теперь все готово к созданию новой таблицы. Снова откройте консоль диспетчера пакетов и на этот раз:

  1. Выполните команду add-migration AddExtraUserInformation.
  2. Выполнение команды update-database

Новая таблица теперь существует в базе данных.

Получение дополнительных данных

Существует два способа получения дополнительных пользовательских данных. Первый способ — сохранить пользовательские данные, которые по умолчанию передаются обратно во время запроса проверки подлинности. Второй способ — вызвать API поставщика и запросить дополнительные сведения. Значения FullName и Link автоматически передаются Обратно Facebook. Значение, указывающее, проверена ли учетная запись Facebook, извлекается с помощью вызова API Facebook. Сначала вы заполните значения FullName и Link, а затем получите проверенное значение.

Чтобы получить дополнительные данные пользователя, откройте файл AccountController.cs в папке Контроллеры .

Этот файл содержит логику для ведения журнала, регистрации учетных записей и управления ими. В частности, обратите внимание на методы ExternalLoginCallback и ExternalLoginConfirmation. В этих методах можно добавить код для настройки внешних операций входа в приложение. Первая строка метода ExternalLoginCallback содержит:

AuthenticationResult result = OAuthWebSecurity.VerifyAuthentication(
    Url.Action("ExternalLoginCallback", new { ReturnUrl = returnUrl }));

Дополнительные данные пользователя передаются обратно в свойство ExtraData объекта AuthenticationResult , возвращаемого методом VerifyAuthentication . Клиент Facebook содержит следующие значения в свойстве ExtraData :

  • идентификатор
  • name
  • link
  • gender
  • accesstoken

Другие поставщики будут иметь аналогичные, но немного другие данные в свойстве ExtraData.

Если пользователь не знакомы с вашим сайтом, вы получите дополнительные данные и передайте их в представление подтверждения. Последний блок кода в методе выполняется только в том случае, если пользователь не знакомы с вашим сайтом. Замените следующую строку:

return View("ExternalLoginConfirmation", new RegisterExternalLoginModel 
{ 
    UserName = result.UserName, 
    ExternalLoginData = loginData 
});

Вставьте вместо нее эту строку:

return View("ExternalLoginConfirmation", new RegisterExternalLoginModel
{
    UserName = result.UserName,
    ExternalLoginData = loginData,
    FullName = result.ExtraData["name"],
    Link = result.ExtraData["link"]
});

Это изменение просто включает значения для свойств FullName и Link.

В методе ExternalLoginConfirmation измените код, как показано ниже, чтобы сохранить дополнительные сведения о пользователе.

if (user == null)
{
    // Insert name into the profile table
    UserProfile newUser = db.UserProfiles.Add(new UserProfile { UserName = model.UserName });
    db.SaveChanges();

    db.ExternalUsers.Add(new ExternalUserInformation 
    { 
        UserId = newUser.UserId, 
        FullName = model.FullName, 
        Link = model.Link 
    });
    db.SaveChanges();

    OAuthWebSecurity.CreateOrUpdateAccount(provider, providerUserId, model.UserName);
    OAuthWebSecurity.Login(provider, providerUserId, createPersistentCookie: false);

    return RedirectToLocal(returnUrl);
}
else
{
    ModelState.AddModelError("UserName", "User name already exists. Please enter a different user name.");
}

Настройка представления

Дополнительные пользовательские данные, полученные от поставщика, будут отображаться на странице регистрации.

В папке"Учетная записьпредставлений/" откройте externalLoginConfirmation.cshtml. Под существующим полем для имени пользователя добавьте поля FullName, Link и PictureLink.

<li>
    @Html.LabelFor(m => m.FullName)
    @Html.TextBoxFor(m => m.FullName)
</li>
<li>
    @Html.LabelFor(m => m.Link)
    @Html.TextBoxFor(m => m.Link)
</li>

Теперь вы почти готовы к запуску приложения и регистрации нового пользователя с сохраненными дополнительными сведениями. У вас должна быть учетная запись, которая еще не зарегистрирована на сайте. Вы можете использовать другую тестовую учетную запись или удалить строки в таблицах UserProfile и webpages_OAuthMembership для учетной записи, которую вы хотите использовать повторно. Удалив эти строки, вы убедитесь, что учетная запись зарегистрирована снова.

Запустите приложение и зарегистрируйте нового пользователя. Обратите внимание, что на этот раз страница подтверждения содержит дополнительные значения.

Снимок экрана: где можно ввести имя пользователя и другие сведения после связывания учетной записи Facebook с приложением.

После завершения регистрации закройте браузер. Просмотрите базу данных, чтобы заметить новые значения в таблице ExtraUserInformation .

Установка пакета NuGet для API Facebook

Facebook предоставляет API , который можно вызывать для выполнения операций. Api Facebook можно вызвать либо путем отправки HTTP-запросов, либо путем установки пакета NuGet, который упрощает отправку этих запросов. Использование пакета NuGet описано в этом руководстве, но установка пакета NuGet не является обязательной. В этом руководстве показано, как использовать пакет SDK для Facebook для C#. Существуют и другие пакеты NuGet, которые помогают вызывать API Facebook.

В окне Управление пакетами NuGet выберите пакет SDK для Facebook C#.

установка пакета

Вы будете использовать пакет SDK для Facebook C# для вызова операции, которая требует маркера доступа для пользователя. В следующем разделе показано, как получить маркер доступа.

Получение маркера доступа

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

В зависимости от внешнего поставщика маркер доступа может быть действителен в течение ограниченного периода времени. Чтобы убедиться, что у вас есть действительный маркер доступа, вы будете получать его каждый раз, когда пользователь входит в систему, и сохранять его как значение сеанса, а не сохранять в базе данных.

В методе ExternalLoginCallback маркер доступа также передается обратно в свойство ExtraData объекта AuthenticationResult . Добавьте выделенный код в ExternalLoginCallback , чтобы сохранить маркер доступа в объекте Session . Этот код выполняется каждый раз, когда пользователь входит в систему с помощью учетной записи Facebook.

[AllowAnonymous]
public ActionResult ExternalLoginCallback(string returnUrl)
{
    AuthenticationResult result = OAuthWebSecurity.VerifyAuthentication(
        Url.Action("ExternalLoginCallback", new { ReturnUrl = returnUrl }));
    if (!result.IsSuccessful)
    {
        return RedirectToAction("ExternalLoginFailure");
    }

    if (result.ExtraData.Keys.Contains("accesstoken"))
    {
        Session["facebooktoken"] = result.ExtraData["accesstoken"];
    }

    if (OAuthWebSecurity.Login(
        result.Provider, 
        result.ProviderUserId, 
        createPersistentCookie: false))
    {
        return RedirectToLocal(returnUrl);
    }

    if (User.Identity.IsAuthenticated)
    {
        // If the current user is logged in add the new account
        OAuthWebSecurity.CreateOrUpdateAccount(
            result.Provider,
            result.ProviderUserId, 
            User.Identity.Name);
        return RedirectToLocal(returnUrl);
    }
    else
    {
        // User is new, ask for their desired membership name
        string loginData = OAuthWebSecurity.SerializeProviderUserId(
            result.Provider, 
            result.ProviderUserId);
        ViewBag.ProviderDisplayName =
            OAuthWebSecurity.GetOAuthClientData(result.Provider).DisplayName;
        ViewBag.ReturnUrl = returnUrl;
        return View("ExternalLoginConfirmation", new RegisterExternalLoginModel
        {
            UserName = result.UserName,
            ExternalLoginData = loginData,
            FullName = result.ExtraData["name"],
            Link = result.ExtraData["link"]
        });    
    }
}

Хотя в этом примере маркер доступа извлекается из Facebook, маркер доступа можно получить от любого внешнего поставщика с помощью того же ключа с именем accesstoken.

выход из системы;

Метод LogOff по умолчанию регистрирует пользователя из приложения, но не выходит из внешнего поставщика. Чтобы вывести пользователя из Facebook и предотвратить сохранение маркера после выхода пользователя из системы, можно добавить следующий выделенный код в метод LogOff в AccountController.

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult LogOff()
{
    WebSecurity.Logout();
    if (Session["facebooktoken"] != null)
    {
        var fb = new Facebook.FacebookClient();
        string accessToken = Session["facebooktoken"] as string;
        var logoutUrl = fb.GetLogoutUrl(new { access_token = accessToken, next = "http://localhost:39852/" });

        Session.RemoveAll();
        return Redirect(logoutUrl.AbsoluteUri);
    }

    return RedirectToAction("Index", "Home");
}

Значение, указанное в параметре next , — это URL-адрес, используемый после выхода пользователя из Facebook. При тестировании на локальном компьютере необходимо указать правильный номер порта для локального сайта. В рабочей среде необходимо указать страницу по умолчанию, например contoso.com.

Получение сведений о пользователе, для которого требуется маркер доступа

Теперь, когда вы сохранили маркер доступа и установили пакет SDK для Facebook для C#, вы можете использовать их вместе для запроса дополнительных сведений о пользователе из Facebook. В методе ExternalLoginConfirmation создайте экземпляр класса FacebookClient , передав значение маркера доступа. Запросите значение проверенного свойства для текущего пользователя, прошедшего проверку подлинности. Свойство verified указывает, проверил ли Facebook учетную запись с помощью других средств, таких как отправка сообщения на мобильный телефон. Сохраните это значение в базе данных.

if (user == null)
{
    // Insert name into the profile table
    UserProfile newUser = db.UserProfiles.Add(new UserProfile { UserName = model.UserName });
    db.SaveChanges();

    bool facebookVerified;

    var client = new Facebook.FacebookClient(Session["facebooktoken"].ToString());
    dynamic response = client.Get("me", new { fields = "verified" });
    if (response.ContainsKey("verified"))
    {
        facebookVerified = response["verified"];
    }
    else
    {
        facebookVerified = false;
    }

    db.ExternalUsers.Add(new ExternalUserInformation 
    { 
        UserId = newUser.UserId, 
        FullName = model.FullName, 
        Link = model.Link, 
        Verified = facebookVerified 
    });
    db.SaveChanges();

    OAuthWebSecurity.CreateOrUpdateAccount(provider, providerUserId, model.UserName);
    OAuthWebSecurity.Login(provider, providerUserId, createPersistentCookie: false);

    return RedirectToLocal(returnUrl);
}

Вам снова потребуется удалить записи в базе данных для пользователя или использовать другую учетную запись Facebook.

Запустите приложение и зарегистрируйте нового пользователя. Просмотрите таблицу ExtraUserInformation , чтобы увидеть значение свойства Verified.

Заключение

В этом руководстве вы создали сайт, интегрированный с Facebook для проверки подлинности и регистрации пользователей. Вы узнали о поведении по умолчанию, которое настраивается для веб-приложения MVC 4, и о том, как настроить это поведение по умолчанию.