作者 :瑞克·安德森
本教學將展示如何打造一個 ASP.NET MVC 5 網頁應用程式,讓使用者能使用外部認證提供者(如 Facebook、Twitter、LinkedIn、Microsoft 或 Google)的憑證登入 OAuth 2.0 。 為了簡化,這個教學重點是使用 Facebook 和 Google 的憑證。
在您的網站上啟用這些憑證,帶來顯著優勢,因為數百萬用戶已在這些外部服務提供商擁有帳號。 如果這些使用者不必建立並記住一組新的憑證,他們可能更願意註冊你的網站。
另見 ASP.NET MVC 5 應用程式中的 SMS 與電子郵件雙因素驗證。
教學也展示了如何為使用者新增個人資料資料,以及如何使用會員 API 新增角色。 這個教學由 Rick Anderson 撰寫(請在 Twitter 上追蹤我: @RickAndMSFT )。
使用者入門
首先安裝並執行 Visual Studio Express 2013 for Web 或Visual Studio 2013。 安裝 Visual Studio 2013 更新 3 或更高版本。
備註
你必須安裝 Visual Studio 2013 更新版 3 或更新版本,才能使用 Google OAuth 2 並在本地除錯而不會觸發 SSL 警告。
從開始頁面點選新專案,或是使用選單選擇「檔案」,然後再選擇「新專案」。
建立你的第一個應用程式
點選 新專案,然後在左側選擇 Visual C# ,再選 網頁ASP.NET 再選擇網頁應用程式。 將專案命名為「MvcAuth」,然後點擊 確定。
在 新 ASP.NET 專案 對話框中,點擊 MVC。 如果驗證不是 個人使用者帳號,請點擊 變更驗證 按鈕並選擇 個人使用者帳號。 選擇 雲端中的 Host,應用程式會更容易在 Azure 上架設。
如果你選擇雲端 主機,請完成設定對話框。
使用 NuGet 更新到最新的 OWIN 中介軟體
使用 NuGet 套件管理器來更新 OWIN 中介軟體。 在左側選單選擇 更新 。 你可以點擊 「全部更新 」按鈕,或只搜尋 OWIN 套件(如下張圖片所示):
下圖僅顯示 OWIN 套件:
你可以在套件管理主控台(PMC)輸入 Update-Package 指令,更新所有套件。
按 F5 或 Ctrl+F5 即可執行該應用程式。 下方圖片中的埠號為 1234。 當你執行應用程式時,你會看到不同的埠號。
根據瀏覽器視窗大小,您可能需要點擊導覽圖示,才能看到 首頁、 關於、 聯絡、 註冊 和 登入 連結。
在專案中設定 SSL
要連接像 Google 和 Facebook 這樣的認證服務提供者,你需要設定使用 SSL IIS-Express。 登入後繼續使用 SSL 很重要,不要降級到 HTTP。你的登入 Cookie 與使用者名稱和密碼都屬於一樣重要的秘密,若未使用 SSL,則是在以明文形式傳輸。 況且,你在 MVC 管線執行之前已經花時間進行握手並保護通道安全(這是 HTTPS 比 HTTP 慢的主要原因),所以在登入後再切換回 HTTP 進行重新導向,不會讓目前的請求或未來的請求變得更快。
在 解決方案檔案總管中,點選 MvcAuth 專案。
按 F4 鍵即可顯示專案屬性。 或者,從 檢視 選單中你可以選擇 屬性視窗。
將 SSL 啟用 改為 true。
複製 SSL URL (這個 URL 預設為
https://localhost:44300/,除非您建立了其他 SSL 專案)。在 解決方案總管中,右鍵點選 MvcAuth 專案並選擇 屬性。
選擇 網頁 分頁,然後將 SSL URL 貼上到 專案網址 框中。 儲存檔案(Ctl+S)。 你需要這個網址來設定 Facebook 和 Google 的認證應用程式。
在控制器上新增 RequireHttps 屬性
Home,要求所有請求都必須使用 HTTPS。 更安全的做法是將 RequireHttps 過濾器加到應用程式中。 請參閱我教學中「用 SSL 和授權屬性保護應用程式」的章節,「 建立一個 ASP.NET MVC 應用程式,搭配認證和 SQL DB,部署到 Azure App Service」。 Home 控制器的部分內容如下所示。[RequireHttps] public class HomeController : Controller { public ActionResult Index() { return View(); }按 CTRL+F5 執行應用程式。 如果你之前已經安裝過該憑證,可以跳過本節剩下的部分,直接跳到 「為 OAuth 2 建立 Google 應用程式並將應用程式與專案連結」,否則,請依照指示信任 IIS Express 產生的自簽憑證。
閱讀 安全警告 對話框,然後點 選「是 」以安裝代表 localhost 的憑證。
IE 瀏覽器顯示 首頁,且沒有 SSL 警告。
Google Chrome 也接受該憑證,並會無警告地顯示 HTTPS 內容。 Firefox 使用自己的憑證儲存庫,因此會顯示警告。 您可以放心點擊 「我了解風險」來申請我們的申請。
為 OAuth 2 建立 Google 應用程式並將該應用程式與專案連結
警告
關於目前 Google OAuth 的說明,請參見 在 ASP.NET Core 中設定 Google 認證。
進入 Google 開發者主控台。
如果你之前沒建立過專案,請在左側分頁選擇 憑證 ,然後選擇 建立。
在左側分頁,點選 憑證。
點選 建立憑證 ,然後點選 OAuth 客戶端 ID。
- 在 「建立用戶端 ID 」對話框中,保留該應用程式類型的預設 網頁應用程式 。
- 請將 授權的 JavaScript 來源設定為你上面使用的 SSL URL(
https://localhost:44300/除非你有建立其他 SSL 專案)。 - 將 授權重定向 URI 設定為:
https://localhost:44300/signin-google
點選 OAuth 同意畫面選單項目,然後設定您的電子郵件地址和產品名稱。 填寫表單後,點擊 儲存。
點選函式庫選單項目,搜尋 Google+ API,點進去,然後按下啟用。
下圖顯示已啟用的 API。
從 Google API API Manager 中,請造訪 憑證 標籤以取得 用戶端 ID。 下載以儲存帶有應用程式秘密的 JSON 檔案。 將 ClientID 和 ClientSecret 複製並貼上到
UseGoogleAuthenticationApp_Start 資料夾裡 Startup.Auth.cs 檔案中找到的方法。 下方顯示的 ClientID 和 ClientSecret 值是範例,無法正常運作。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 App Service 的最佳實務。
按 CTRL+F5 即可建置並執行應用程式。 點擊 登入 連結。
在 「使用其他服務登入」中,點選 Google。
備註
如果你漏掉上述任何步驟,將會收到 HTTP 401 錯誤。 請重看上面的步驟。 如果你漏掉了必須設定(例如 產品名稱),就新增缺少的項目並儲存;認證可能需要幾分鐘才能生效。
您將被導向至 Google 網站,輸入您的憑證。
輸入憑證後,系統會提示你對剛建立的網頁應用程式授予權限:
按一下 [接受]。 您現在會被導回 MvcAuth 應用程式的 註冊 頁面,在那裡您可以註冊您的 Google 帳號。 你可以選擇更改 Gmail 帳號使用的本地電子郵件註冊名稱,但通常你會想保留預設的電子郵件別名(也就是你用來驗證的那個)。 按一下 [註冊]。
在 Facebook 建立應用程式並將應用程式與專案連結
警告
關於目前的 Facebook OAuth2 認證說明,請參見 設定 Facebook 認證
使用伺服器檔案總管檢視會員資料
在 檢視 選單中,點選 伺服器檔案總管。
展開 DefaultConnection (MvcAuth),展開 資料表,右鍵點選 AspNetUsers,然後點選顯示資料表數據。
將個人資料加入使用者類別
在此區塊中,註冊時你會將出生日期和家鄉加入使用者資料,如下圖所示。
打開 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再點「刪除」。
在 工具 選單中,點選 NuGet 套件管理器,然後點選 套件管理員主控台 (PMC)。 在 PMC 中輸入以下指令。
- Enable-Migrations
- Add-Migration 開始
- Update-Database
啟動應用程式,使用 Facebook 和 Google 登入並註冊一些使用者。
檢視會員資料
在 檢視 選單中,點選 伺服器檔案總管。
右鍵點 選 AspNetUsers ,然後點 選「顯示資料表資料」。
HomeTown與 BirthDate 欄位如下所示。
登出你的應用程式並用其他帳號登入
如果你用 Facebook 登入你的應用程式,然後登出再嘗試用不同的 Facebook 帳號(使用同一瀏覽器)登入,你會立刻登入到你之前使用的 Facebook 帳號。 要使用其他帳號,你需要先進入 Facebook 並登出。 同樣的規則也適用於任何其他第三方驗證服務提供者。 或者,你也可以用不同的瀏覽器登入另一個帳號。
後續步驟
請跟著我的教學「 建立一個 ASP.NET MVC 應用程式,包含認證和 SQL DB,並部署到 Azure App Service」,該教學會延續這個教學並展示以下內容:
- 如何將你的應用程式部署到 Azure。
- 如何用角色來保障你的應用程式。
- 如何用 RequireHttps 和 Authorize 篩選器保護你的應用程式。
- 如何使用會員 API 來新增使用者和角色。
關於外部認證服務 ASP.NET 如何運作,請參見 Robert McMurray 的 《外部驗證服務》。 Robert 的文章也詳細說明了如何啟用 Microsoft 和 Twitter 的認證。 Tom Dykstra 優秀的 EF/MVC 教學 展示了如何使用 Entity Framework 工作。