创建 ASP.NET MVC 5 应用,实现 Facebook、Twitter、LinkedIn 和 Google OAuth2 登录 (C#)

作者 :Rick Anderson

本教程介绍如何构建 ASP.NET MVC 5 Web 应用程序,使用户能够使用来自外部身份验证提供程序(如 Facebook、Twitter、LinkedIn、Microsoft 或 Google)的凭据使用 OAuth 2.0 登录。 为简单起见,本教程重点介绍如何使用来自 Facebook 和 Google 的凭据。

在网站中启用这些凭据具有显著优势,因为数百万用户已经拥有这些外部提供商的帐户。 如果这些用户不必创建并记住一组新的凭据,则他们可能更倾向于注册您的网站。

另请参阅 使用短信和电子邮件Two-Factor身份验证 ASP.NET MVC 5 应用

本教程还演示如何为用户添加配置文件数据,以及如何使用成员资格 API 添加角色。 本教程由 Rick Anderson (请在 Twitter 上关注我: @RickAndMSFT ) 。

入门

首先安装并运行 Visual Studio Express 2013 for WebVisual Studio 2013。 安装 Visual Studio 2013 Update 3 或更高版本。

注意

必须安装 Visual Studio 2013 Update 3 或更高版本才能使用 Google OAuth 2 并在本地调试而不显示 SSL 警告。

单击“开始”页中的“新建项目”,或者可以使用菜单选择“文件”,然后选择“新建项目”。

显示 Visual Studio“开始”页的屏幕截图。

创建第一个应用程序

单击“ 新建项目”,在左侧依次选择“ Visual C# ”、“ Web ”和“ ASP.NET Web 应用程序”。 将项目命名为“MvcAuth”,然后单击“ 确定”。

显示 Visual Studio“新建项目”菜单页的屏幕截图。M v c 身份验证在“名称”文本字段中输入。

“新建 ASP.NET 项目 ”对话框中,单击“ MVC”。 如果“身份验证”不是 “个人用户帐户”,请单击“ 更改身份验证 ”按钮并选择“ 个人用户帐户”。 通过检查 云中的主机,应用将很容易在 Azure 中托管。

显示“新建 S P 点 NET 项目”对话框的屏幕截图。突出显示了“更改身份验证”按钮和“在云中托管”复选框。

如果选择了“ 在云中托管”,请完成“配置”对话框。

显示“配置 Microsoft Azure 网站”对话框的屏幕截图。输入示例数据库密码。

使用 NuGet 更新到最新的 OWIN 中间件

使用 NuGet 包管理器更新 OWIN 中间件。 在左侧菜单中选择“汇报”。 可以单击“ 全部更新 ”按钮,也可以仅搜索下一张图像) 中显示的 OWIN 包 (:

显示“管理 Nu GET 包”对话框的屏幕截图。突出显示了汇报栏和“全部更新”按钮。

在下图中,仅显示 OWIN 包:

显示“管理 Nu GET 包”对话框的屏幕截图。突出显示了“汇报栏”和“搜索栏”,其中输入了“OWN”。

在包管理器控制台 (PMC) ,可以输入 Update-Package 命令,这将更新所有包。

F5Ctrl+F5 运行应用程序。 在下图中,端口号为 1234。 运行应用程序时,会看到不同的端口号。

根据浏览器窗口的大小,可能需要单击导航图标才能看到 “主页”、“ 关于”、“ 联系人”、“ 注册 ”和 “登录” 链接。

显示“我的 A S P 点 NET 主页”的屏幕截图。“导航”图标突出显示。
显示“我的 A S P 点 NET 主页”的屏幕截图。突出显示并选中“导航”图标,其中显示了包含导航链接的下拉菜单。

在项目中设置 SSL

若要连接到 Google 和 Facebook 等身份验证提供程序,需要设置IIS-Express才能使用 SSL。 请务必在登录后继续使用 SSL,而不是回退到 HTTP,登录 Cookie 与用户名和密码一样机密,如果不使用 SSL,你将通过网络以明文形式发送它。 此外,你已花时间执行握手并保护通道 (这是使 HTTPS 比运行 MVC 管道之前 HTTP) 慢的大部分,因此在登录后重定向回 HTTP 不会使当前请求或将来的请求速度更快。

  1. “解决方案资源管理器”中,单击“MvcAuth”项目。

  2. 点击 F4 键以显示项目属性。 或者,可以从“ 视图 ”菜单中选择“ 属性窗口”。

  3. “已启用 SSL” 更改为“True”。

    显示 M v c 身份验证项目的解决方案资源管理器项目属性的屏幕截图。突出显示了 S S L Enabled True 和 S S L U R L。

  4. 复制 SSL URL (除非 https://localhost:44300/) 创建了其他 SSL 项目。

  5. “解决方案资源管理器”中,右键单击“MvcAuth”项目,然后选择“属性”。

  6. 选择“ Web ”选项卡,然后将 SSL URL 粘贴到“ 项目 URL ”框中。 (Ctl+S) 保存文件。 需要此 URL 才能配置 Facebook 和 Google 身份验证应用。

    显示 M v c Auth 项目的属性页的屏幕截图。突出显示左侧菜单上的“Web”选项卡和“项目 U R L”框中粘贴的 S S L U R L。

  7. RequireHttps 属性添加到控制器, Home 以要求所有请求都必须使用 HTTPS。 更安全的方法是将 RequireHttps 筛选器添加到应用程序。 请参阅我的教程中的“使用 SSL 和授权属性保护应用程序”部分,使用身份验证和 SQL DB 创建 ASP.NET MVC 应用并将其部署到 Azure 应用服务。 主控制器的一部分如下所示。

    [RequireHttps]
    public class HomeController : Controller
    {
       public ActionResult Index()
       {
          return View();
       }
    
  8. 按 Ctrl+F5 运行应用程序。 如果过去安装了证书,则可以跳过本部分的其余部分,跳转到创建适用于 OAuth 2 的 Google 应用并将应用连接到项目,否则,请按照说明信任IIS Express生成的自签名证书。

    显示 Visual Studio 对话框的屏幕截图,提示用户选择是否信任 I S Express S L 证书。

  9. 阅读 “安全警告 ”对话框,如果要安装表示 localhost 的证书,请单击“ ”。

    显示 Visual Studio 安全警告对话框的屏幕截图,提示用户选择是否安装证书。

  10. IE 会显示“主页”页面,而且不会出现 SSL 警告。

    显示没有 S S L 警告的“我的 A S P 点 NET 主页”的屏幕截图。

  11. Google Chrome 也会接受证书,并且不出现警告便显示 HTTPS 内容。 Firefox 会使用自己的证书存储区,因此会显示警告。 对于我们的应用程序,可以安全地单击“ 我了解风险”。

    显示 Firefox 上运行的 My A S P dot NET 应用的屏幕截图。“不受信任的连接”警告页询问用户是否接受应用程序并继续。

为 OAuth 2 创建 Google 应用,并将应用连接到项目

警告

有关当前的 Google OAuth 说明,请参阅在 ASP.NET Core 中配置 Google 身份验证

  1. 导航到 Google 开发人员控制台

  2. 如果之前尚未创建项目,请在左侧选项卡中选择“ 凭据 ”,然后选择“ 创建”。

  3. 在左侧选项卡中,单击“ 凭据”。

  4. 单击 “创建凭据 ”,然后单击 “OAuth 客户端 ID”。

    1. “创建客户端 ID ”对话框中,保留应用程序类型的默认 Web 应用程序。
    2. 授权的 JavaScript 源设置为上面使用的 SSL URL (https://localhost:44300/ 除非已创建其他 SSL 项目)
    3. “授权的重定向 URI ”设置为:
      https://localhost:44300/signin-google
  5. 单击“OAuth 许可”屏幕菜单项,然后设置电子邮件地址和产品名称。 完成表单后,单击“ 保存”。

  6. 单击“库”菜单项,搜索 Google+ API,单击它,然后按“启用”。

    显示搜索结果列表的屏幕截图。突出显示了 Google 加 A P I 搜索结果。

    下图显示了已启用的 API。

    显示已启用 A P I 的 Google 开发人员控制台页面列表的屏幕截图。当其旁边出现绿色的 ON 按钮时,P I 显示为已启用。

  7. 在 Google API API 管理器中,访问“ 凭据 ”选项卡以获取 客户端 ID。 下载以保存包含应用程序机密的 JSON 文件。 将 ClientIdClientSecret 复制并粘贴到 UseGoogleAuthenticationApp_Start 文件夹中的 Startup.Auth.cs 文件中的方法中。 下面显示的 ClientIdClientSecret 值是示例,不起作用。

    public void ConfigureAuth(IAppBuilder app)
    {
        // Configure the db context and user manager to use a single instance per request
        app.CreatePerOwinContext(ApplicationDbContext.Create);
        app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
    
        // Enable the application to use a cookie to store information for the signed in user
        // and to use a cookie to temporarily store information about a user logging in with a third party login provider
        // Configure the sign in cookie
        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            LoginPath = new PathString("/Account/Login"),
            Provider = new CookieAuthenticationProvider
            {
                OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                    validateInterval: TimeSpan.FromMinutes(30),
                    regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
            }
        });
        
        app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
    
        // Uncomment the following lines to enable logging in with third party login providers
        //app.UseMicrosoftAccountAuthentication(
        //    clientId: "",
        //    clientSecret: "");
    
        //app.UseTwitterAuthentication(
        //   consumerKey: "",
        //   consumerSecret: "");
    
        //app.UseFacebookAuthentication(
        //   appId: "",
        //   appSecret: "");
    
        app.UseGoogleAuthentication(
             clientId: "000-000.apps.googleusercontent.com",
             clientSecret: "00000000000");
    }
    

    警告

    安全性 - 切勿将敏感数据存储在源代码中。 帐户和凭据将添加到上述代码中,使示例保持简单。 请参阅将密码和其他敏感数据部署到 ASP.NET 和Azure 应用服务的最佳做法

  8. Ctrl+F5 生成并运行应用程序。 单击“ 登录” 链接。

    显示“我的 A S P 点 NET 主页”的屏幕截图。突出显示了“导航”按钮和“登录”链接。

  9. “使用其他服务登录”下,单击“ Google”。

    显示“我的 A S P dot NET 登录”页的屏幕截图。突出显示了“使用其他服务登录”对话框和“Google”按钮。

    注意

    如果错过上述任何步骤,将收到 HTTP 401 错误。 重新检查上述步骤。 如果缺少所需的设置 (例如 产品名称) ,请添加缺少的项目并保存;身份验证可能需要几分钟才能正常工作。

  10. 你将重定向到 Google 站点,你将在其中输入凭据。

    显示 Google 帐户登录页的屏幕截图。示例凭据在文本字段中输入。

  11. 输入你的凭据后,系统将提示你刚创建的 Web 应用程序,以便授予其权限:

    显示 Google 帐户请求权限页面的屏幕截图,提示用户取消或接受对 Web 应用程序的脱机访问。

  12. 单击“接受”。 现在,你将重定向回 MvcAuth 应用程序的 “注册 ”页,可在其中注册 Google 帐户。 你可以选择更改 Gmail 帐户使用的本地电子邮件注册名称,但是,你通常会保留默认电子邮件别名(即,用于身份验证的名称)。 单击“注册”。

    显示“我的 A S P dot NET 注册应用程序”页的屏幕截图。在电子邮件文本字段中输入示例 Google 帐户。

在 Facebook 中创建应用并将应用连接到项目

警告

有关当前的 Facebook OAuth2 身份验证说明,请参阅 配置 Facebook 身份验证

使用服务器资源管理器检查成员身份数据

在“ 视图 ”菜单中,单击“ 服务器资源管理器”。

显示 Visual Studio“视图”下拉菜单的屏幕截图,其中突出显示了“服务器资源管理器”。

展开 “DefaultConnection (MvcAuth) ”,展开“ ”,右键单击“ AspNetUsers ”,然后单击“ 显示表数据”。

显示服务资源管理器菜单选项的屏幕截图。展开了“数据连接”、“默认连接 M v c 身份验证”和“表”选项卡。

aspnetusers 表数据

将配置文件数据添加到 User 类

在本部分中,你将在注册期间将出生日期和家乡添加到用户数据中,如下图所示。

与家乡和 Bday 一起注册

打开 Models\IdentityModels.cs 文件并添加出生日期和家乡属性:

public class ApplicationUser : IdentityUser
{
    public string HomeTown { get; set; }
    public System.DateTime? BirthDate { get; set; }
    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
    {
        // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
        var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
        // Add custom user claims here
        return userIdentity;
    }
}

打开 Models\AccountViewModels.cs 文件,并在 中 ExternalLoginConfirmationViewModel设置出生日期和家乡属性。

public class ExternalLoginConfirmationViewModel
{
    [Required]
    [EmailAddress]
    [Display(Name = "Email")]
    public string Email { get; set; }

    public string HomeTown { get; set; }
    public System.DateTime? BirthDate { get; set; }
}

打开 Controllers\AccountController.cs 文件,并在操作方法中添加 ExternalLoginConfirmation 出生日期和家乡的代码,如下所示:

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> ExternalLoginConfirmation(ExternalLoginConfirmationViewModel model, string returnUrl)
{
    if (User.Identity.IsAuthenticated)
    {
        return RedirectToAction("Manage");
    }

    if (ModelState.IsValid)
    {
        // Get the information about the user from the external login provider
        var info = await AuthenticationManager.GetExternalLoginInfoAsync();
        if (info == null)
        {
            return View("ExternalLoginFailure");
        }
        var user = new ApplicationUser() 
        {
            UserName = model.Email, Email = model.Email,
            BirthDate = model.BirthDate,
            HomeTown  = model.HomeTown
        
        };
        IdentityResult result = await UserManager.CreateAsync(user);
        if (result.Succeeded)
        {
            result = await UserManager.AddLoginAsync(user.Id, info.Login);
            if (result.Succeeded)
            {
                await SignInAsync(user, isPersistent: false);
                
                // For more information on how to enable account confirmation and password reset please visit https://go.microsoft.com/fwlink/?LinkID=320771
                // Send an email with this link
                // string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
                // var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
                // SendEmail(user.Email, callbackUrl, "Confirm your account", "Please confirm your account by clicking this link");
                
                return RedirectToLocal(returnUrl);
            }
        }
        AddErrors(result);
    }

    ViewBag.ReturnUrl = returnUrl;
    return View(model);
}

将出生日期和家乡添加到 Views\Account\ExternalLoginConfirmation.cshtml 文件:

@model MvcAuth.Models.ExternalLoginConfirmationViewModel
@{
    ViewBag.Title = "Register";
}
<h2>@ViewBag.Title.</h2>
<h3>Associate your @ViewBag.LoginProvider account.</h3>

@using (Html.BeginForm("ExternalLoginConfirmation", "Account", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
{
    @Html.AntiForgeryToken()

    <h4>Association Form</h4>
    <hr />
    @Html.ValidationSummary(true, "", new { @class = "text-danger" })
    <p class="text-info">
        You've successfully authenticated with <strong>@ViewBag.LoginProvider</strong>.
            Please enter a user name for this site below and click the Register button to finish
            logging in.
    </p>
    <div class="form-group">
        @Html.LabelFor(m => m.Email, new { @class = "col-md-2 control-label" })
        <div class="col-md-10">
            @Html.TextBoxFor(m => m.Email, new { @class = "form-control" })
            @Html.ValidationMessageFor(m => m.Email, "", new { @class = "text-danger" })
        </div>
    </div>
    <div class="form-group">
        @Html.LabelFor(m => m.HomeTown, new { @class = "col-md-2 control-label" })
        <div class="col-md-10">
            @Html.TextBoxFor(m => m.HomeTown, new { @class = "form-control" })
            @Html.ValidationMessageFor(m => m.HomeTown)
        </div>
    </div>
    <div class="form-group">
        @Html.LabelFor(m => m.BirthDate, new { @class = "col-md-2 control-label" })
        <div class="col-md-10">
            @Html.TextBoxFor(m => m.BirthDate, new { @class = "form-control" })
            @Html.ValidationMessageFor(m => m.BirthDate)
        </div>
    </div>
    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <input type="submit" class="btn btn-default" value="Register" />
        </div>
    </div>
}

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

删除成员资格数据库,以便再次向应用程序注册 Facebook 帐户,并验证是否可以添加新的出生日期和家乡个人资料信息。

解决方案资源管理器中,单击“显示所有文件”图标,然后右键单击“Add_Data\aspnet-MvcAuth-dateStamp.mdf<>”,然后单击“删除”。

显示“解决方案资源管理器”页的屏幕截图。突出显示了“显示所有文件”图标和 M v c 身份验证成员资格数据库。

“工具 ”菜单中,单击“ NuGet 包管理器”,然后单击“ 包管理器控制台 ” (PMC) 。 在 PMC 中输入以下命令。

  1. Enable-Migrations
  2. Add-Migration Init
  3. Update-Database

运行应用程序并使用 FaceBook 和 Google 登录并注册某些用户。

检查成员身份数据

在“ 视图 ”菜单中,单击“ 服务器资源管理器”。

显示 Visual Studio“视图”下拉菜单的屏幕截图。突出显示了“服务资源管理器”选项。

右键单击“ AspNetUsers ”,然后单击“ 显示表数据”。

显示“服务器资源管理器”菜单选项的屏幕截图。突出显示了“A”p Net Users“和”显示表数据“选项。

HomeTownBirthDate 字段如下所示。

显示 A s p Net Users 表数据的屏幕截图。表数据显示 ID、家乡、出生日期、Email和Email确认字段。

注销应用并使用其他帐户登录

如果你使用 Facebook 登录到应用,然后注销并尝试使用相同的浏览器) 使用不同的 Facebook 帐户再次登录 (,你将立即登录到以前使用的 Facebook 帐户。 若要使用其他帐户,需要导航到 Facebook 并在 Facebook 注销。 同一规则适用于任何其他第三方身份验证提供程序。 或者,可以使用其他浏览器使用其他帐户登录。

后续步骤

按照我的教程创建具有身份验证和 SQL DB 的 ASP.NET MVC 应用并部署到 Azure 应用服务,继续本教程并显示以下内容:

  1. 如何将应用部署到 Azure。
  2. 如何使用角色保护应用。
  3. 如何使用 RequireHttpsAuthorize 筛选器保护应用。
  4. 如何使用成员资格 API 添加用户和角色。

有关外部身份验证服务 ASP.NET 工作原理的详细说明,请参阅 Robert McMurray 的外部身份验证服务。 Robert 的文章还详细介绍了启用 Microsoft 和 Twitter 身份验证。 Tom Dykstra 出色的 EF/MVC 教程 介绍了如何使用实体框架。