ASP.NET MVC 4 使用 OAuth
這個教程向你展示了如何創建一個ASP.NET MVC 4的web應用,能讓用戶用外部提供方的證書(比如Facebook, Twitter, Microsoft,或Google)登陸,然后將源自那些提供方的一些功能集成進你的web應用。為簡單起見,本教程主要講述與Facebook的證書一起工作。
在你的web應用中啟用這些證書提供了一個重要的優勢,因為數百萬用戶已經有這些外部提供方的帳號。如果不是必須創建並且記住一組新的證書,這些用戶可能更傾向於注冊你的網站。而且當一個用戶通過某一個提供方登陸以后,你可以引入提供方的社會化動作。
你將需要構建的
本指南主要有兩個目標:
- 使用戶可以通過開放授權服務者提供的憑據登錄
- 從第三方獲取賬號信息並通過在你的站點上完善賬戶信息
雖然本文的例子只演示了將facebook作為授權服務提供者,但是你可以修改代碼去使用任意一個第三方的服務提供者.那些實現的步驟會合你在本文中看到的非常類似.你只有在直接調用第三方提供的API集合時才會發現一些顯著的差異.
先決條件
- Microsoft Visual Studio 2012 或r Microsoft Visual Studio Express 2012 for Web
- Microsoft Visual Studio 2010 SP1 或 Visual Web Developer Express 2010 SP1
- ASP.NET MVC 4
而且,本文假設你具有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是否驗證了該帳號的一個值。
你將使用代碼首先遷移來增加一個表,以便存儲附加用戶信息。你在增加表到已存在的數據庫,因此首先你需要創建一個當前數據庫的快照。通過創建當前數據庫的快照,你可以以后創建一個僅包含新增表的遷移。要創建當前數據庫快照:
- 打開 Package Manager Console
- 運行命令 enable-migrations
- 運行命令 add-migration initial –IgnoreChanges
- 運行命令 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 { get ; set ; } |
06 |
07 |
public string ExternalLoginData { get ; set ; } |
08 |
09 |
[Display(Name = "Full name" )] |
10 |
public string FullName { get ; set ; } |
11 |
12 |
[Display(Name = "Personal page link" )] |
13 |
public string Link { get ; set ; } |
14 |
} |
同樣在AccountModels.cs, 增加一個名為ExtraUserInformation的新類。這個類代表了將在數據庫創建的新表。
1 |
[Table( "ExtraUserInformation" )] |
2 |
public class ExternalUserInformation |
3 |
{ |
4 |
public int Id { get ; set ; } |
5 |
public int UserId { get ; set ; } |
6 |
public string FullName { get ; set ; } |
7 |
public string Link { get ; set ; } |
8 |
public bool ? Verified { get ; set ; } |
9 |
} |
在UsersContext類里,增加下面突出的代碼,為新類創建一個DbSet屬性。
01 |
public class UsersContext : DbContext |
02 |
{ |
03 |
public UsersContext() |
04 |
: base ( "DefaultConnection" ) |
05 |
{ |
06 |
} |
07 |
08 |
public DbSet<UserProfile> UserProfiles { get ; set ; } |
09 |
public DbSet<ExternalUserInformation> ExternalUsers { get ; set ; } |
10 |
} |
現在你准備好創建新表了。再次打開 Package Manager Console,這次:
- 運行命令 add-migration AddExtraUserInformation
- 運行命令 update-database
新表現在在數據庫出現了。
取得附加的數據
有兩個方法獲得附加的用戶數據。第一個是保留返回的用戶數據,默認是在鑒權請求的過程中。第二個方法是特定的調用提供方的 API並請求更多的信息。FullName 與 Link的值自動被Facebook返回。Facebook是否已驗證帳號的一個表示數值,是通過一次對Facebook API的調用獲得的。首先你要為FullName 和 Link填充值,在此之后,你會得到驗證的值。
為了獲得額外的用戶數據, 打開在Controllers 目錄的 AccountController.cs 文件。
這個文件包含了登錄、注冊以及管理帳號的邏輯。特別的,注意名為ExternalLoginCallback和ExternalLoginConfirmation的方法。在這些方法內,你為你的應用可增加客制化的外部登錄操作代碼。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" , new RegisterExternalLoginModel |
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( new ExternalUserInformation |
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 |
} |
調整視圖
你從提供方獲得的附加的用戶數據將被顯示於注冊頁面。
在 Views/ Account 目錄,打開 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 > |
現在你幾乎已經准備好運行應用,並且用保存的附加信息注冊一個新用戶。你必須有一個尚未在該網站注冊的帳號。你可以使用一個不同的測試帳號,也可以刪除UserProfile和webpages_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( new ExternalUserInformation |
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應用中啟用這些證書提供了一個重要的優勢,因為數百萬用戶已經有這些外部提供方的帳號。如果不是必須創建並且記住一組新的證書,這些用戶可能更傾向於注冊你的網站。而且當一個用戶通過某一個提供方登陸以后,你可以引入提供方的社會化動作。
你將需要構建的
本指南主要有兩個目標:
- 使用戶可以通過開放授權服務者提供的憑據登錄
- 從第三方獲取賬號信息並通過在你的站點上完善賬戶信息
雖然本文的例子只演示了將facebook作為授權服務提供者,但是你可以修改代碼去使用任意一個第三方的服務提供者.那些實現的步驟會合你在本文中看到的非常類似.你只有在直接調用第三方提供的API集合時才會發現一些顯著的差異.
先決條件
- Microsoft Visual Studio 2012 或r Microsoft Visual Studio Express 2012 for Web
- Microsoft Visual Studio 2010 SP1 或 Visual Web Developer Express 2010 SP1
- ASP.NET MVC 4
而且,本文假設你具有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是否驗證了該帳號的一個值。
你將使用代碼首先遷移來增加一個表,以便存儲附加用戶信息。你在增加表到已存在的數據庫,因此首先你需要創建一個當前數據庫的快照。通過創建當前數據庫的快照,你可以以后創建一個僅包含新增表的遷移。要創建當前數據庫快照:
- 打開 Package Manager Console
- 運行命令 enable-migrations
- 運行命令 add-migration initial –IgnoreChanges
- 運行命令 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 { get ; set ; } |
06 |
07 |
public string ExternalLoginData { get ; set ; } |
08 |
09 |
[Display(Name = "Full name" )] |
10 |
public string FullName { get ; set ; } |
11 |
12 |
[Display(Name = "Personal page link" )] |
13 |
public string Link { get ; set ; } |
14 |
} |
同樣在AccountModels.cs, 增加一個名為ExtraUserInformation的新類。這個類代表了將在數據庫創建的新表。
1 |
[Table( "ExtraUserInformation" )] |
2 |
public class ExternalUserInformation |
3 |
{ |
4 |
public int Id { get ; set ; } |
5 |
public int UserId { get ; set ; } |
6 |
public string FullName { get ; set ; } |
7 |
public string Link { get ; set ; } |
8 |
public bool ? Verified { get ; set ; } |
9 |
} |
在UsersContext類里,增加下面突出的代碼,為新類創建一個DbSet屬性。
01 |
public class UsersContext : DbContext |
02 |
{ |
03 |
public UsersContext() |
04 |
: base ( "DefaultConnection" ) |
05 |
{ |
06 |
} |
07 |
08 |
public DbSet<UserProfile> UserProfiles { get ; set ; } |
09 |
public DbSet<ExternalUserInformation> ExternalUsers { get ; set ; } |
10 |
} |
現在你准備好創建新表了。再次打開 Package Manager Console,這次:
- 運行命令 add-migration AddExtraUserInformation
- 運行命令 update-database
新表現在在數據庫出現了。
取得附加的數據
有兩個方法獲得附加的用戶數據。第一個是保留返回的用戶數據,默認是在鑒權請求的過程中。第二個方法是特定的調用提供方的 API並請求更多的信息。FullName 與 Link的值自動被Facebook返回。Facebook是否已驗證帳號的一個表示數值,是通過一次對Facebook API的調用獲得的。首先你要為FullName 和 Link填充值,在此之后,你會得到驗證的值。
為了獲得額外的用戶數據, 打開在Controllers 目錄的 AccountController.cs 文件。
這個文件包含了登錄、注冊以及管理帳號的邏輯。特別的,注意名為ExternalLoginCallback和ExternalLoginConfirmation的方法。在這些方法內,你為你的應用可增加客制化的外部登錄操作代碼。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" , new RegisterExternalLoginModel |
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( new ExternalUserInformation |
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 |
} |
調整視圖
你從提供方獲得的附加的用戶數據將被顯示於注冊頁面。
在 Views/ Account 目錄,打開 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 > |
現在你幾乎已經准備好運行應用,並且用保存的附加信息注冊一個新用戶。你必須有一個尚未在該網站注冊的帳號。你可以使用一個不同的測試帳號,也可以刪除UserProfile和webpages_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( new ExternalUserInformation |
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應用創立的默認的行為,以及如何客制化那個默認的行為。