ASP.NET MVC 4 使用 OAuth

这个教程向你展示了如何创建一个ASP.NET MVC 4的web应用,能让用户用外部提供方的证书(比如Facebook, Twitter, Microsoft,或Google)登陆,然后将源自那些提供方的一些功能集成进你的web应用。为简单起见,本教程主要讲述与Facebook的证书一起工作。

在你的web应用中启用这些证书提供了一个重要的优势,因为数百万用户已经有这些外部提供方的帐号。如果不是必须创建并且记住一组新的证书,这些用户可能更倾向于注册你的网站。而且当一个用户通过某一个提供方登陆以后,你可以引入提供方的社会化动作。

你将需要构建的

本指南主要有两个目标:

  1. 使用户可以通过开放授权服务者提供的凭据登录
  2. 从第三方获取账号信息并通过在你的站点上完善账户信息

虽然本文的例子只演示了将facebook作为授权服务提供者,但是你可以修改代码去使用任意一个第三方的服务提供者.那些实现的步骤会合你在本文中看到的非常类似.你只有在直接调用第三方提供的API集合时才会发现一些显著的差异.

先决条件

而且,本文假设你具有ASP.NET MVC与Visual Studio的基础知识。如果你需要一个ASP.NET MVC 4的介绍, 请看 ASP.NET MVC 4介绍.

创建工程

在Visual Studio里创建一个新的 ASP.NET MVC 4 Web Application,命名它为 "OAuthMVC"。你可以选择目标为.NET Framework 4.5 或 4中任意一个。

在 New ASP.NET MVC 4 Project 窗口, 选择 Internet Application 并保留 Razor 作为视图引擎。

启用一个提供者

当你用Internet Application模板创建出一个MVC 4 web application时,这个工程在App_Start目录创建了一个名为AuthConfig.cs的文件。

AuthConfig文件包含了针对外部证书提供方的客户注册代码。默认情况下,这些代码被注释掉了,所以没有外部提供者被启用。

01 public static class AuthConfig
02 {
03     public static void RegisterAuth()
04     {
05         // To let users of this site log in using their accounts from other sites such as Microsoft, Facebook, and Twitter,
06         // you must update this site. For more information visit http://go.microsoft.com/fwlink/?LinkID=252166
07  
08         //OAuthWebSecurity.RegisterMicrosoftClient(
09         //    clientId: "",
10         //    clientSecret: "");
11  
12         //OAuthWebSecurity.RegisterTwitterClient(
13         //    consumerKey: "",
14         //    consumerSecret: "");
15  
16         //OAuthWebSecurity.RegisterFacebookClient(
17         //    appId: "",
18         //    appSecret: "");
19  
20         //OAuthWebSecurity.RegisterGoogleClient();
21     }
22 }

你必须反注册这些代码,以便使用外部的客户证书。你只需反注册你想纳入你的网站的提供方。对本教程,你只要启用Facebook证书。

01 public static class AuthConfig
02 {
03     public static void RegisterAuth()
04     {
05         //OAuthWebSecurity.RegisterMicrosoftClient(
06         //    clientId: "",
07         //    clientSecret: "");
08  
09         //OAuthWebSecurity.RegisterTwitterClient(
10         //    consumerKey: "",
11         //    consumerSecret: "");
12  
13         OAuthWebSecurity.RegisterFacebookClient(
14             appId: "",
15             appSecret: "");
16  
17         //OAuthWebSecurity.RegisterGoogleClient();       
18     }
19 }

注意上面的例子,方法包含了注册参数的空字符串。如果你想现在运行这个应用,应用会抛出一个参数异常,因为这个参数不允许空字符串。为了给出合法的值,你必须像下一节显示的那样,在外部提供方注册你的网站。

在外部提供方注册

要通过来自外部提供方的证书鉴定用户,你必须在提供方注册你的网站。当你注册你的网站时,你将会收到一些参数(比如key或id,以及密码),以便注册客户时包含进去。你必须在你想使用的提供方有一个帐号。

本教程没有呈现出在这些提供方进行注册的所有必须的操作步骤。这些步骤通常是不难的。为了成功的注册你的网站,按照那些网站提供的指示去做。要开始注册你的网站,看看这些开发者网站:

在Facebook注册你的网站时,你可以规定"localhost"为网站域名,"http://localhost/"为网址,像下面图片显示的那样。使用localhost对大多数提供方有效,但目前对Microsoft提供方无效。对Microsoft提供方,你必须包含一个合法的web网站地址。

在前面的图片中,app id,app secret 和contact email的值被剔除了。当你真正注册你的网站时,那些值将会显现。你要注意app id 和app secret的值,因为你将会把它们加到你的应用,

创建测试用户

如果你不介意使用一个已存在的Facebook帐号来测试你的网站,你可以跳过本节。

你能很容易的在Facebook app管理页面中,为你的应用创建测试用户。你能用这些测试帐号登录你的网站。创建测试用户要点击左边导航格子的Roles链接,并点击Create链接。

Facebook网站自动创建你申请的数目的测试帐号。

给应用添加来自提供方的id与secret

现在你收到了来自Facebook的id和secret,回到AuthConfig文件把它们作为参数值增加进去。下面显示的数值不是真实的数值。

01 public static class AuthConfig
02 {
03     public static void RegisterAuth()
04     {
05         //OAuthWebSecurity.RegisterMicrosoftClient(
06         //    clientId: "",
07         //    clientSecret: "");
08  
09         //OAuthWebSecurity.RegisterTwitterClient(
10         //    consumerKey: "",
11         //    consumerSecret: "");
12  
13         OAuthWebSecurity.RegisterFacebookClient(
14             appId: "111111111111111",
15             appSecret: "a1a1aa111111111a111a111aaa111111");
16  
17         //OAuthWebSecurity.RegisterGoogleClient();
18     }
19 }

用外部证书登录

那就是在你的网站启用外部证书全部要做的。运行你的应用点击右上角的login链接。模版自动识别出你注册了Facebook作为提供方,并为这个提供方包含了一个按钮。如果你注册了多个提供方,一个按钮对应一个会自动包括进来。

本教程没有覆盖怎样为外部提供方客制化登录按钮。需要那些信息,可以看使用OAuth/OpenID时客制化登录界面。

点击Facebook按钮以Facebook证书登录。当你选择了外部提供方的一个,你将被重定向到那个网站,并在其服务提示下登录。

下图显示了Facebook的登录界面。它标明你在用名为oauthmvcexample的Facebook帐号登录一个网站。

用Facebook证书登录以后,一个页面告诉用户这个网站将访问其基本的信息。

选择 Go to App以后, 用户必须在该网站注册。下图显示了一个用户用Facebook证书登录以后的注册页面。用户名被典型的用一个来自提供方的名字预填充。

点击 Register 完成注册。关闭浏览器。

你可以看到新的帐号已经被加到你的数据库。在Server Explorer里,打开DefaultConnection数据库并打开Tables目录。

右击 UserProfile 表选择 Show Table Data

你将看到你增加的新帐号。看看webpage_OAuthMembership表中的数据。你会看到为你刚增加的帐号,有关外部提供方的的更多数据。

如果你只是想启用外部鉴权,你已经完成了。然而你可以进一步将来自提供方的信息集成进新用户注册过程,就像下面几节显示的那样。

为附加的用户信息创建模型

正如你在前面几节注意到的,你不需要获得任何附加的信息来使内建的注册去工作。但是,大多数提供方返回了关于用户的附加信息。下面几节显示了怎样保留该信息并将它存入数据库。特别的,你将保留这些值,用户的全名,用户个人主页的URI,以及表明Facebook是否验证了该帐号的一个值。

你将使用代码首先迁移来增加一个表,以便存储附加用户信息。你在增加表到已存在的数据库,因此首先你需要创建一个当前数据库的快照。通过创建当前数据库的快照,你可以以后创建一个仅包含新增表的迁移。要创建当前数据库快照:

  1. 打开 Package Manager Console
  2. 运行命令 enable-migrations
  3. 运行命令 add-migration initial –IgnoreChanges
  4. 运行命令 update-database

现在你要增加新的属性。在Models目录,打开AccountModels.cs文件,找到RegisterExternalLoginModel类。RegisterExternalLoginModel类持有由鉴权提供方返回的数值。增加名为FullName 与 Link的属性,像下面突出的那样。

01 public class RegisterExternalLoginModel
02 {
03     [Required]
04     [Display(Name = "User name")]
05     public string UserName { getset; }
06  
07     public string ExternalLoginData { getset; }
08  
09     [Display(Name = "Full name")]
10     public string FullName { getset; }
11  
12     [Display(Name = "Personal page link")]
13     public string Link { getset; }
14 }

同样在AccountModels.cs, 增加一个名为ExtraUserInformation的新类。这个类代表了将在数据库创建的新表。

1 [Table("ExtraUserInformation")]
2 public class ExternalUserInformation
3 {
4     public int Id { getset; }
5     public int UserId { getset; }
6     public string FullName { getset; }
7     public string Link { getset; }
8     public bool? Verified { getset; }
9 }

在UsersContext类里,增加下面突出的代码,为新类创建一个DbSet属性。

01 public class UsersContext : DbContext
02 {
03     public UsersContext()
04         base("DefaultConnection")
05     {
06     }
07  
08     public DbSet<UserProfile> UserProfiles { getset; }
09     public DbSet<ExternalUserInformation> ExternalUsers { getset; }
10 }

现在你准备好创建新表了。再次打开 Package Manager Console,这次:

  1. 运行命令 add-migration AddExtraUserInformation
  2. 运行命令 update-database

新表现在在数据库出现了。

取得附加的数据

有两个方法获得附加的用户数据。第一个是保留返回的用户数据,默认是在鉴权请求的过程中。第二个方法是特定的调用提供方的 API并请求更多的信息。FullName 与 Link的值自动被Facebook返回。Facebook是否已验证帐号的一个表示数值,是通过一次对Facebook API的调用获得的。首先你要为FullName 和 Link填充值,在此之后,你会得到验证的值。

为了获得额外的用户数据, 打开在Controllers 目录的 AccountController.cs 文件。

这个文件包含了登录、注册以及管理帐号的逻辑。特别的,注意名为ExternalLoginCallbackExternalLoginConfirmation的方法。在这些方法内,你为你的应用可增加客制化的外部登录操作代码。ExternalLoginCallback方法第一行包含:

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

额外的用户数据在AuthenticationResult对象的ExtraData属性中返回,该对象由VerifyAuthentication方法返回。Facebook在ExtraData属性中包含了下面一些值:

  • id
  • name
  • link
  • gender
  • accesstoken

其他提供方在ExtraData属性中有类似但稍许不同的数据。

如果用户是你的网站的新用户,你会获得一些额外的数据并将其传给确认视图。该方法的最后一块代码只在用户是你网站的新用户 时运行。替代下面这行:

1 return View("ExternalLoginConfirmation"newRegisterExternalLoginModel
2 {
3     UserName = result.UserName,
4     ExternalLoginData = loginData
5 });

替换为这行:

1 return View("ExternalLoginConfirmation"new RegisterExternalLoginModel
2 {
3     UserName = result.UserName,
4     ExternalLoginData = loginData,
5     FullName = result.ExtraData["name"],
6     Link = result.ExtraData["link"]
7 });

这个修改只是包括了FullName 与 Link属性的值。

ExternalLoginConfirmation 方法里,像下面突出显示的那样修改代码,以便保存附加的用户信息。

01 if (user == null)
02 {
03     // Insert name into the profile table
04     UserProfile newUser = db.UserProfiles.Add(new UserProfile { UserName = model.UserName });
05     db.SaveChanges();
06  
07     db.ExternalUsers.Add(newExternalUserInformation
08     {
09         UserId = newUser.UserId,
10         FullName = model.FullName,
11         Link = model.Link
12     });
13     db.SaveChanges();
14  
15     OAuthWebSecurity.CreateOrUpdateAccount(provider, providerUserId, model.UserName);
16     OAuthWebSecurity.Login(provider, providerUserId, createPersistentCookie: false);
17  
18     return RedirectToLocal(returnUrl);
19 }
20 else
21 {
22     ModelState.AddModelError("UserName""User name already exists. Please enter a different user name.");
23 }

调整视图

你从提供方获得的附加的用户数据将被显示于注册页面。

在 ViewsAccount 目录,打开 ExternalLoginConfirmation.cshtml。在已存在的user name字段下面,增加FullName, Link, 和 PictureLink字段。

1 <li>
2     @Html.LabelFor(m => m.FullName)
3     @Html.TextBoxFor(m => m.FullName)
4 </li>
5 <li>
6     @Html.LabelFor(m => m.Link)
7     @Html.TextBoxFor(m => m.Link)
8 </li>

现在你几乎已经准备好运行应用,并且用保存的附加信息注册一个新用户。你必须有一个尚未在该网站注册的帐号。你可以使用一个不同的测试帐号,也可以删除UserProfilewebpages_OAuthMembership 表中的你想重新使用的帐号对应行。通过删除那些行,你能确保该帐号能再次注册。

运行应用并注册新用户。注意这次确认页面包含了更多的数值。

完成注册以后,关闭浏览器。看看数据库,留心ExtraUserInformation表中的新的值。

为Facebook API安装NuGet包

Facebook 提供了一个 API 给你调用来执行操作。你可以或者通过直接发送HTTP请求,或者通过安装一个帮助发送那些请求的NuGet包,来调用Facebook API。使用一个NuGet包已被本教程显示,但安装NuGet包不是基本的。这个教程显示了如何使用Facebook C# SDK包。还有其他的辅助Facebook API调用的NuGet包。

从 Manage NuGet Packages 窗口,选择 Facebook C# SDK package。

你将使用 Facebook C# SDK 来调用一个操作,该操作请求用户的 access token (访问令牌)。下一节显示了如何得到access token。

取得 access token

大多数外部的提供方在用户鉴权被验证以后返回一个access token。这个access token非常重要,因为它使你可以调用只能被鉴权用户使用的操作。因此,当你想提供更多功能性时,获得并保存access token是基本的。

取决于外部的提供方,access token可能只在一个有限数值的时间内有效。为了确保你具有一个有效的access token,你要在每次用户登录的时候获得它,并将它保存为session值而不是保存进数据库。

在 ExternalLoginCallback 方法里,access token也被送回到AuthenticationResult对象的ExtraData属性。添加如下突出的代码到 ExternalLoginCallback 以便将 access token 保存进 Session 对象。这些代码在每次用户用Facebook帐号登录时会运行。

01 [AllowAnonymous]
02 public ActionResult ExternalLoginCallback(string returnUrl)
03 {
04     AuthenticationResult result = OAuthWebSecurity.VerifyAuthentication(
05         Url.Action("ExternalLoginCallback"new { ReturnUrl = returnUrl }));
06     if (!result.IsSuccessful)
07     {
08         return RedirectToAction("ExternalLoginFailure");
09     }
10  
11     if (result.ExtraData.Keys.Contains("accesstoken"))
12     {
13         Session["facebooktoken"] = result.ExtraData["accesstoken"];
14     }
15  
16     if (OAuthWebSecurity.Login(
17         result.Provider,
18         result.ProviderUserId,
19         createPersistentCookie: false))
20     {
21         return RedirectToLocal(returnUrl);
22     }
23  
24     if (User.Identity.IsAuthenticated)
25     {
26         // If the current user is logged in add the new account
27         OAuthWebSecurity.CreateOrUpdateAccount(
28             result.Provider,
29             result.ProviderUserId,
30             User.Identity.Name);
31         return RedirectToLocal(returnUrl);
32     }
33     else
34     {
35         // User is new, ask for their desired membership name
36         string loginData = OAuthWebSecurity.SerializeProviderUserId(
37             result.Provider,
38             result.ProviderUserId);
39         ViewBag.ProviderDisplayName =
40             OAuthWebSecurity.GetOAuthClientData(result.Provider).DisplayName;
41         ViewBag.ReturnUrl = returnUrl;
42         return View("ExternalLoginConfirmation"new RegisterExternalLoginModel
43         {
44             UserName = result.UserName,
45             ExternalLoginData = loginData,
46             FullName = result.ExtraData["name"],
47             Link = result.ExtraData["link"]
48         });   
49     }
50 }

尽管这个例子从Facebook获得了一个access token,你可以通过同样的名为“accesstoken”的关键字从任何外部提供方获得access token。

为了防止令牌在用户已退出登录以后仍然保持,你可以添加如下突出的代码到AccountController中的 LogOff方法。

1 [HttpPost]
2 [ValidateAntiForgeryToken]
3 public ActionResult LogOff()
4 {
5     WebSecurity.Logout();
6     Session.Remove("facebooktoken");
7  
8     return RedirectToAction("Index""Home");
9 }

获得需要访问令牌的用户信息

现在你已经保存了access token并且安装了Facebook C# SDK包,你可以一起使用它们去从Facebook请求附加的用户信息。在ExternalLoginConfirmation方法中,通过传递access token的值创建了一个FacebookClient类的实例。请求当前鉴权用户的verified属性值。verified属性表明了Facebook是否已经通过一些其他的方法,比如给蜂窝电话发送一个信息,验证了该帐号。将这个数值保存进数据库。

01 if (user == null)
02 {
03     // Insert name into the profile table
04     UserProfile newUser = db.UserProfiles.Add(new UserProfile { UserName = model.UserName });
05     db.SaveChanges();
06  
07     bool facebookVerified;
08  
09     var client = new Facebook.FacebookClient(Session["facebooktoken"].ToString());
10     dynamic response = client.Get("me"new { fields = "verified" });
11     if (response.ContainsKey("verified"))
12     {
13         facebookVerified = response["verified"];
14     }
15     else
16     {
17         facebookVerified = false;
18     }
19  
20     db.ExternalUsers.Add(newExternalUserInformation
21     {
22         UserId = newUser.UserId,
23         FullName = model.FullName,
24         Link = model.Link,
25         Verified = facebookVerified
26     });
27     db.SaveChanges();
28  
29     OAuthWebSecurity.CreateOrUpdateAccount(provider, providerUserId, model.UserName);
30     OAuthWebSecurity.Login(provider, providerUserId, createPersistentCookie: false);
31  
32     return RedirectToLocal(returnUrl);
33 }

你将需要再一次或者删除数据库中用户的记录,或者使用一个不同的Facebook帐号。

运行应用,并且注册新用户。看看ExtraUserInformation表 Verified属性的值。

总结

本教程中,你创建了集成Facebook来进行用户鉴权并注册数据的网站。你学习了MVC4 web应用创立的默认的行为,以及如何客制化那个默认的行为。

ASP.NET MVC 4 使用 OAuth

这个教程向你展示了如何创建一个ASP.NET MVC 4的web应用,能让用户用外部提供方的证书(比如Facebook, Twitter, Microsoft,或Google)登陆,然后将源自那些提供方的一些功能集成进你的web应用。为简单起见,本教程主要讲述与Facebook的证书一起工作。

在你的web应用中启用这些证书提供了一个重要的优势,因为数百万用户已经有这些外部提供方的帐号。如果不是必须创建并且记住一组新的证书,这些用户可能更倾向于注册你的网站。而且当一个用户通过某一个提供方登陆以后,你可以引入提供方的社会化动作。

你将需要构建的

本指南主要有两个目标:

  1. 使用户可以通过开放授权服务者提供的凭据登录
  2. 从第三方获取账号信息并通过在你的站点上完善账户信息

虽然本文的例子只演示了将facebook作为授权服务提供者,但是你可以修改代码去使用任意一个第三方的服务提供者.那些实现的步骤会合你在本文中看到的非常类似.你只有在直接调用第三方提供的API集合时才会发现一些显著的差异.

先决条件

而且,本文假设你具有ASP.NET MVC与Visual Studio的基础知识。如果你需要一个ASP.NET MVC 4的介绍, 请看 ASP.NET MVC 4介绍.

创建工程

在Visual Studio里创建一个新的 ASP.NET MVC 4 Web Application,命名它为 "OAuthMVC"。你可以选择目标为.NET Framework 4.5 或 4中任意一个。

在 New ASP.NET MVC 4 Project 窗口, 选择 Internet Application 并保留 Razor 作为视图引擎。

启用一个提供者

当你用Internet Application模板创建出一个MVC 4 web application时,这个工程在App_Start目录创建了一个名为AuthConfig.cs的文件。

AuthConfig文件包含了针对外部证书提供方的客户注册代码。默认情况下,这些代码被注释掉了,所以没有外部提供者被启用。

01 public static class AuthConfig
02 {
03     public static void RegisterAuth()
04     {
05         // To let users of this site log in using their accounts from other sites such as Microsoft, Facebook, and Twitter,
06         // you must update this site. For more information visit http://go.microsoft.com/fwlink/?LinkID=252166
07  
08         //OAuthWebSecurity.RegisterMicrosoftClient(
09         //    clientId: "",
10         //    clientSecret: "");
11  
12         //OAuthWebSecurity.RegisterTwitterClient(
13         //    consumerKey: "",
14         //    consumerSecret: "");
15  
16         //OAuthWebSecurity.RegisterFacebookClient(
17         //    appId: "",
18         //    appSecret: "");
19  
20         //OAuthWebSecurity.RegisterGoogleClient();
21     }
22 }

你必须反注册这些代码,以便使用外部的客户证书。你只需反注册你想纳入你的网站的提供方。对本教程,你只要启用Facebook证书。

01 public static class AuthConfig
02 {
03     public static void RegisterAuth()
04     {
05         //OAuthWebSecurity.RegisterMicrosoftClient(
06         //    clientId: "",
07         //    clientSecret: "");
08  
09         //OAuthWebSecurity.RegisterTwitterClient(
10         //    consumerKey: "",
11         //    consumerSecret: "");
12  
13         OAuthWebSecurity.RegisterFacebookClient(
14             appId: "",
15             appSecret: "");
16  
17         //OAuthWebSecurity.RegisterGoogleClient();       
18     }
19 }

注意上面的例子,方法包含了注册参数的空字符串。如果你想现在运行这个应用,应用会抛出一个参数异常,因为这个参数不允许空字符串。为了给出合法的值,你必须像下一节显示的那样,在外部提供方注册你的网站。

在外部提供方注册

要通过来自外部提供方的证书鉴定用户,你必须在提供方注册你的网站。当你注册你的网站时,你将会收到一些参数(比如key或id,以及密码),以便注册客户时包含进去。你必须在你想使用的提供方有一个帐号。

本教程没有呈现出在这些提供方进行注册的所有必须的操作步骤。这些步骤通常是不难的。为了成功的注册你的网站,按照那些网站提供的指示去做。要开始注册你的网站,看看这些开发者网站:

在Facebook注册你的网站时,你可以规定"localhost"为网站域名,"http://localhost/"为网址,像下面图片显示的那样。使用localhost对大多数提供方有效,但目前对Microsoft提供方无效。对Microsoft提供方,你必须包含一个合法的web网站地址。

在前面的图片中,app id,app secret 和contact email的值被剔除了。当你真正注册你的网站时,那些值将会显现。你要注意app id 和app secret的值,因为你将会把它们加到你的应用,

创建测试用户

如果你不介意使用一个已存在的Facebook帐号来测试你的网站,你可以跳过本节。

你能很容易的在Facebook app管理页面中,为你的应用创建测试用户。你能用这些测试帐号登录你的网站。创建测试用户要点击左边导航格子的Roles链接,并点击Create链接。

Facebook网站自动创建你申请的数目的测试帐号。

给应用添加来自提供方的id与secret

现在你收到了来自Facebook的id和secret,回到AuthConfig文件把它们作为参数值增加进去。下面显示的数值不是真实的数值。

01 public static class AuthConfig
02 {
03     public static void RegisterAuth()
04     {
05         //OAuthWebSecurity.RegisterMicrosoftClient(
06         //    clientId: "",
07         //    clientSecret: "");
08  
09         //OAuthWebSecurity.RegisterTwitterClient(
10         //    consumerKey: "",
11         //    consumerSecret: "");
12  
13         OAuthWebSecurity.RegisterFacebookClient(
14             appId: "111111111111111",
15             appSecret: "a1a1aa111111111a111a111aaa111111");
16  
17         //OAuthWebSecurity.RegisterGoogleClient();
18     }
19 }

用外部证书登录

那就是在你的网站启用外部证书全部要做的。运行你的应用点击右上角的login链接。模版自动识别出你注册了Facebook作为提供方,并为这个提供方包含了一个按钮。如果你注册了多个提供方,一个按钮对应一个会自动包括进来。

本教程没有覆盖怎样为外部提供方客制化登录按钮。需要那些信息,可以看使用OAuth/OpenID时客制化登录界面。

点击Facebook按钮以Facebook证书登录。当你选择了外部提供方的一个,你将被重定向到那个网站,并在其服务提示下登录。

下图显示了Facebook的登录界面。它标明你在用名为oauthmvcexample的Facebook帐号登录一个网站。

用Facebook证书登录以后,一个页面告诉用户这个网站将访问其基本的信息。

选择 Go to App以后, 用户必须在该网站注册。下图显示了一个用户用Facebook证书登录以后的注册页面。用户名被典型的用一个来自提供方的名字预填充。

点击 Register 完成注册。关闭浏览器。

你可以看到新的帐号已经被加到你的数据库。在Server Explorer里,打开DefaultConnection数据库并打开Tables目录。

右击 UserProfile 表选择 Show Table Data

你将看到你增加的新帐号。看看webpage_OAuthMembership表中的数据。你会看到为你刚增加的帐号,有关外部提供方的的更多数据。

如果你只是想启用外部鉴权,你已经完成了。然而你可以进一步将来自提供方的信息集成进新用户注册过程,就像下面几节显示的那样。

为附加的用户信息创建模型

正如你在前面几节注意到的,你不需要获得任何附加的信息来使内建的注册去工作。但是,大多数提供方返回了关于用户的附加信息。下面几节显示了怎样保留该信息并将它存入数据库。特别的,你将保留这些值,用户的全名,用户个人主页的URI,以及表明Facebook是否验证了该帐号的一个值。

你将使用代码首先迁移来增加一个表,以便存储附加用户信息。你在增加表到已存在的数据库,因此首先你需要创建一个当前数据库的快照。通过创建当前数据库的快照,你可以以后创建一个仅包含新增表的迁移。要创建当前数据库快照:

  1. 打开 Package Manager Console
  2. 运行命令 enable-migrations
  3. 运行命令 add-migration initial –IgnoreChanges
  4. 运行命令 update-database

现在你要增加新的属性。在Models目录,打开AccountModels.cs文件,找到RegisterExternalLoginModel类。RegisterExternalLoginModel类持有由鉴权提供方返回的数值。增加名为FullName 与 Link的属性,像下面突出的那样。

01 public class RegisterExternalLoginModel
02 {
03     [Required]
04     [Display(Name = "User name")]
05     public string UserName { getset; }
06  
07     public string ExternalLoginData { getset; }
08  
09     [Display(Name = "Full name")]
10     public string FullName { getset; }
11  
12     [Display(Name = "Personal page link")]
13     public string Link { getset; }
14 }

同样在AccountModels.cs, 增加一个名为ExtraUserInformation的新类。这个类代表了将在数据库创建的新表。

1 [Table("ExtraUserInformation")]
2 public class ExternalUserInformation
3 {
4     public int Id { getset; }
5     public int UserId { getset; }
6     public string FullName { getset; }
7     public string Link { getset; }
8     public bool? Verified { getset; }
9 }

在UsersContext类里,增加下面突出的代码,为新类创建一个DbSet属性。

01 public class UsersContext : DbContext
02 {
03     public UsersContext()
04         base("DefaultConnection")
05     {
06     }
07  
08     public DbSet<UserProfile> UserProfiles { getset; }
09     public DbSet<ExternalUserInformation> ExternalUsers { getset; }
10 }

现在你准备好创建新表了。再次打开 Package Manager Console,这次:

  1. 运行命令 add-migration AddExtraUserInformation
  2. 运行命令 update-database

新表现在在数据库出现了。

取得附加的数据

有两个方法获得附加的用户数据。第一个是保留返回的用户数据,默认是在鉴权请求的过程中。第二个方法是特定的调用提供方的 API并请求更多的信息。FullName 与 Link的值自动被Facebook返回。Facebook是否已验证帐号的一个表示数值,是通过一次对Facebook API的调用获得的。首先你要为FullName 和 Link填充值,在此之后,你会得到验证的值。

为了获得额外的用户数据, 打开在Controllers 目录的 AccountController.cs 文件。

这个文件包含了登录、注册以及管理帐号的逻辑。特别的,注意名为ExternalLoginCallbackExternalLoginConfirmation的方法。在这些方法内,你为你的应用可增加客制化的外部登录操作代码。ExternalLoginCallback方法第一行包含:

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

额外的用户数据在AuthenticationResult对象的ExtraData属性中返回,该对象由VerifyAuthentication方法返回。Facebook在ExtraData属性中包含了下面一些值:

  • id
  • name
  • link
  • gender
  • accesstoken

其他提供方在ExtraData属性中有类似但稍许不同的数据。

如果用户是你的网站的新用户,你会获得一些额外的数据并将其传给确认视图。该方法的最后一块代码只在用户是你网站的新用户 时运行。替代下面这行:

1 return View("ExternalLoginConfirmation"newRegisterExternalLoginModel
2 {
3     UserName = result.UserName,
4     ExternalLoginData = loginData
5 });

替换为这行:

1 return View("ExternalLoginConfirmation"new RegisterExternalLoginModel
2 {
3     UserName = result.UserName,
4     ExternalLoginData = loginData,
5     FullName = result.ExtraData["name"],
6     Link = result.ExtraData["link"]
7 });

这个修改只是包括了FullName 与 Link属性的值。

ExternalLoginConfirmation 方法里,像下面突出显示的那样修改代码,以便保存附加的用户信息。

01 if (user == null)
02 {
03     // Insert name into the profile table
04     UserProfile newUser = db.UserProfiles.Add(new UserProfile { UserName = model.UserName });
05     db.SaveChanges();
06  
07     db.ExternalUsers.Add(newExternalUserInformation
08     {
09         UserId = newUser.UserId,
10         FullName = model.FullName,
11         Link = model.Link
12     });
13     db.SaveChanges();
14  
15     OAuthWebSecurity.CreateOrUpdateAccount(provider, providerUserId, model.UserName);
16     OAuthWebSecurity.Login(provider, providerUserId, createPersistentCookie: false);
17  
18     return RedirectToLocal(returnUrl);
19 }
20 else
21 {
22     ModelState.AddModelError("UserName""User name already exists. Please enter a different user name.");
23 }

调整视图

你从提供方获得的附加的用户数据将被显示于注册页面。

在 ViewsAccount 目录,打开 ExternalLoginConfirmation.cshtml。在已存在的user name字段下面,增加FullName, Link, 和 PictureLink字段。

1 <li>
2     @Html.LabelFor(m => m.FullName)
3     @Html.TextBoxFor(m => m.FullName)
4 </li>
5 <li>
6     @Html.LabelFor(m => m.Link)
7     @Html.TextBoxFor(m => m.Link)
8 </li>

现在你几乎已经准备好运行应用,并且用保存的附加信息注册一个新用户。你必须有一个尚未在该网站注册的帐号。你可以使用一个不同的测试帐号,也可以删除UserProfilewebpages_OAuthMembership 表中的你想重新使用的帐号对应行。通过删除那些行,你能确保该帐号能再次注册。

运行应用并注册新用户。注意这次确认页面包含了更多的数值。

完成注册以后,关闭浏览器。看看数据库,留心ExtraUserInformation表中的新的值。

为Facebook API安装NuGet包

Facebook 提供了一个 API 给你调用来执行操作。你可以或者通过直接发送HTTP请求,或者通过安装一个帮助发送那些请求的NuGet包,来调用Facebook API。使用一个NuGet包已被本教程显示,但安装NuGet包不是基本的。这个教程显示了如何使用Facebook C# SDK包。还有其他的辅助Facebook API调用的NuGet包。

从 Manage NuGet Packages 窗口,选择 Facebook C# SDK package。

你将使用 Facebook C# SDK 来调用一个操作,该操作请求用户的 access token (访问令牌)。下一节显示了如何得到access token。

取得 access token

大多数外部的提供方在用户鉴权被验证以后返回一个access token。这个access token非常重要,因为它使你可以调用只能被鉴权用户使用的操作。因此,当你想提供更多功能性时,获得并保存access token是基本的。

取决于外部的提供方,access token可能只在一个有限数值的时间内有效。为了确保你具有一个有效的access token,你要在每次用户登录的时候获得它,并将它保存为session值而不是保存进数据库。

在 ExternalLoginCallback 方法里,access token也被送回到AuthenticationResult对象的ExtraData属性。添加如下突出的代码到 ExternalLoginCallback 以便将 access token 保存进 Session 对象。这些代码在每次用户用Facebook帐号登录时会运行。

01 [AllowAnonymous]
02 public ActionResult ExternalLoginCallback(string returnUrl)
03 {
04     AuthenticationResult result = OAuthWebSecurity.VerifyAuthentication(
05         Url.Action("ExternalLoginCallback"new { ReturnUrl = returnUrl }));
06     if (!result.IsSuccessful)
07     {
08         return RedirectToAction("ExternalLoginFailure");
09     }
10  
11     if (result.ExtraData.Keys.Contains("accesstoken"))
12     {
13         Session["facebooktoken"] = result.ExtraData["accesstoken"];
14     }
15  
16     if (OAuthWebSecurity.Login(
17         result.Provider,
18         result.ProviderUserId,
19         createPersistentCookie: false))
20     {
21         return RedirectToLocal(returnUrl);
22     }
23  
24     if (User.Identity.IsAuthenticated)
25     {
26         // If the current user is logged in add the new account
27         OAuthWebSecurity.CreateOrUpdateAccount(
28             result.Provider,
29             result.ProviderUserId,
30             User.Identity.Name);
31         return RedirectToLocal(returnUrl);
32     }
33     else
34     {
35         // User is new, ask for their desired membership name
36         string loginData = OAuthWebSecurity.SerializeProviderUserId(
37             result.Provider,
38             result.ProviderUserId);
39         ViewBag.ProviderDisplayName =
40             OAuthWebSecurity.GetOAuthClientData(result.Provider).DisplayName;
41         ViewBag.ReturnUrl = returnUrl;
42         return View("ExternalLoginConfirmation"new RegisterExternalLoginModel
43         {
44             UserName = result.UserName,
45             ExternalLoginData = loginData,
46             FullName = result.ExtraData["name"],
47             Link = result.ExtraData["link"]
48         });   
49     }
50 }

尽管这个例子从Facebook获得了一个access token,你可以通过同样的名为“accesstoken”的关键字从任何外部提供方获得access token。

为了防止令牌在用户已退出登录以后仍然保持,你可以添加如下突出的代码到AccountController中的 LogOff方法。

1 [HttpPost]
2 [ValidateAntiForgeryToken]
3 public ActionResult LogOff()
4 {
5     WebSecurity.Logout();
6     Session.Remove("facebooktoken");
7  
8     return RedirectToAction("Index""Home");
9 }

获得需要访问令牌的用户信息

现在你已经保存了access token并且安装了Facebook C# SDK包,你可以一起使用它们去从Facebook请求附加的用户信息。在ExternalLoginConfirmation方法中,通过传递access token的值创建了一个FacebookClient类的实例。请求当前鉴权用户的verified属性值。verified属性表明了Facebook是否已经通过一些其他的方法,比如给蜂窝电话发送一个信息,验证了该帐号。将这个数值保存进数据库。

01 if (user == null)
02 {
03     // Insert name into the profile table
04     UserProfile newUser = db.UserProfiles.Add(new UserProfile { UserName = model.UserName });
05     db.SaveChanges();
06  
07     bool facebookVerified;
08  
09     var client = new Facebook.FacebookClient(Session["facebooktoken"].ToString());
10     dynamic response = client.Get("me"new { fields = "verified" });
11     if (response.ContainsKey("verified"))
12     {
13         facebookVerified = response["verified"];
14     }
15     else
16     {
17         facebookVerified = false;
18     }
19  
20     db.ExternalUsers.Add(newExternalUserInformation
21     {
22         UserId = newUser.UserId,
23         FullName = model.FullName,
24         Link = model.Link,
25         Verified = facebookVerified
26     });
27     db.SaveChanges();
28  
29     OAuthWebSecurity.CreateOrUpdateAccount(provider, providerUserId, model.UserName);
30     OAuthWebSecurity.Login(provider, providerUserId, createPersistentCookie: false);
31  
32     return RedirectToLocal(returnUrl);
33 }

你将需要再一次或者删除数据库中用户的记录,或者使用一个不同的Facebook帐号。

运行应用,并且注册新用户。看看ExtraUserInformation表 Verified属性的值。

总结

本教程中,你创建了集成Facebook来进行用户鉴权并注册数据的网站。你学习了MVC4 web应用创立的默认的行为,以及如何客制化那个默认的行为。

MVC中AuthConfig的作用 -- ASP.NET MVC 4 使用 OAuth的更多相关文章

  1. ASP.NET MVC 学习笔记-7.自定义配置信息 ASP.NET MVC 学习笔记-6.异步控制器 ASP.NET MVC 学习笔记-5.Controller与View的数据传递 ASP.NET MVC 学习笔记-4.ASP.NET MVC中Ajax的应用 ASP.NET MVC 学习笔记-3.面向对象设计原则

    ASP.NET MVC 学习笔记-7.自定义配置信息   ASP.NET程序中的web.config文件中,在appSettings这个配置节中能够保存一些配置,比如, 1 <appSettin ...

  2. Web用户的身份验证及WebApi权限验证流程的设计和实现 asp.net mvc AllowAnonymous 不起作用, asp.net mvc 匿名访问

    原文地址: https://blog.csdn.net/zjlovety/article/details/17095627 前言:Web 用户的身份验证,及页面操作权限验证是B/S系统的基础功能,一个 ...

  3. 【ASP.NET MVC系列】浅谈ASP.NET MVC资源过滤和授权

    最近比较忙,博客很久没更新了,很多博友问何时更新博文,因此,今天就花了点时间,写了本篇文章,但愿大家喜欢. 本篇文章不适合初学者,需要对ASP.NET MVC具有一定基础. 本篇文章主要从ASP.NE ...

  4. 《Entity Framework 6 Recipes》中文翻译系列 (20) -----第四章 ASP.NET MVC中使用实体框架之在MVC中构建一个CRUD示例

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 第四章  ASP.NET MVC中使用实体框架 ASP.NET是一个免费的Web框架 ...

  5. Web 应用程序中的安全向量 – ASP.NET MVC 4 系列

           Web 程序运行在标准的.基于文本的协议(HTTP 和 HTML)之上,所以特别容易受到自动攻击的伤害.本章主要介绍黑客如何滥用应用程序,以及针对这些问题的应对措施.   威胁:跨站脚本 ...

  6. Spring MVC中的DispatcherServlet作用

    一. DispatcherServlet是前端控制器设计模式的实现,提供Spring Web MVC的集中访问点,而且负责职责的分派,而且与Spring IoC容器无缝集成,从而可以获得Spring的 ...

  7. 【ASP.NET MVC系列】浅谈ASP.NET MVC 视图

    ASP.NET MVC系列文章 [01]浅谈Google Chrome浏览器(理论篇) [02]浅谈Google Chrome浏览器(操作篇)(上) [03]浅谈Google Chrome浏览器(操作 ...

  8. ASP.NET MVC案例教程(基于ASP.NET MVC beta)——第六篇:拦截器

    摘要      本文将对“MVC公告发布系统”的发布公告功能添加日志功能和异常处理功能,借此来讨论ASP.NET MVC中拦截器的使用方法. 一个小难题      我们继续完善“MVC公告发布系统”, ...

  9. ASP.NET MVC案例教程(基于ASP.NET MVC beta)——第三篇:ASP.NET MVC全局观

    摘要      本文对ASP.NET MVC的全局运行机理进行一个简要的介绍,以使得朋友们更好的理解后续文章. 前言      在上一篇文章中,我们实现了第一个ASP.NET MVC页面.对于没有接触 ...

随机推荐

  1. Tomcat启动时报错:java.net.UnknownHostException

    异常信息如下: INFO: Failed to get local InetAddress for VMID. This is unlikely to matter. At all. We'll ad ...

  2. InnoDB与MyISAM引擎区别

    mysql中InnoDB与MyISAM两种数据库引擎的区别: 一.InnoDB引擎: 1.支持事务性, 2.支持外部键, 3.行级锁, 4.不保存表的具体行数,执行select count(*) fr ...

  3. java操作mongodb——连接数据库

    import com.mongodb.MongoClient; MongoClient mongoClient = new MongoClient(); 连接MongoDB实例,默认为localhos ...

  4. Beyond Compare V3.2.3 Beta 中文版

    软件名称: Beyond Compare V3.2.3 Beta 中文版 软件语言: 简体中文 授权方式: 免费软件 运行环境: Win7 / Vista / Win2003 / WinXP 软件大小 ...

  5. bat脚本学习

    工作需求,写个bat脚本来启动自己的守护进程:bat方面完全空白啊~稍微学习了下,记录下来,后面复习! 直接上代码: 示例一:for字符串切割,切割文本中的字符串: test.txt 文本内容如下: ...

  6. c#的as关键字

    类型a  as 类型b   ,把类型a强制变为类型b

  7. jenkins 杀死衍生进程

    解决方法-1: 在execute shell输入框中加入BUILD_ID=DONTKILLME,即可防止jenkins衍生进程 解决方法-2: 修改/etc/sysconfig/jenkins配置,在 ...

  8. 常用的html标签大全

    html标签大全 一.文字 1.标题文字 <h#>..........</h#> #=1~6:h1为最大字,h6为最小字 2.字体变化 <font>........ ...

  9. OpenGL编译问题随手记

    1.error C2381: "exit" : 重定义:__declspec(noreturn) 不同 编译OpenGL   Red   Book   的例子时出现错误, stdl ...

  10. 扯蛋css

    使网页旋转代码: javascript:window.i=1;setInterval(function(){i++;document.body.style.cssText+="-webkit ...