摘要:第八次當選 MVP 好開心實作雙因素驗證的一個簡單範例。
Scott Hanselman 前天寫了一篇有關雙因素驗證(two-factor authentication)的文章:Adding Two-Factor authentication to an ASP.NET application,想到自己最近也在專案中實作了雙因素驗證,而發送驗證碼的部分也恰好跟他文章裡的範例一樣是透過 Twilio 發簡訊至手機。
不過,人家是貨真價實的運用 ASP.NET Identity 2.0,我這裡的範例不過就是使用了 IIdentityMessageService 和 IdentityMessage 這兩個型別,充其量只跟 Identity 2.0 沾點邊而已。用來示範雙因素驗證的基本流程以及如何透過 Twilio 服務平台發送簡訊倒是真的。
以下說明實作此範例的步驟。
開發工具:Visual Studio 2013
Step 1. 建立新專案
目標平台:.NET Framework 4.5
專案名稱:TwoFactorAuthDemo
選擇空白專案範本,勾選 Web Forms:
另外再加入 jQuery 2.x 套件,並於 Global.asax.cs 中撰寫 Application_Start 方法:
Step 2:建立登入頁面
New 一個 Web Form,取名為 Login.aspx。從 Toolbox 拖拉一個 Login 控制項至網頁上,然後撰寫該控制項的 Authenticate 事件處理函式:
我把身分驗證的邏輯寫在 Services 資料夾下的 AuthenticationService 類別裡,該類別的 AuthenticateAndSendToken 方法會負責檢查帳號密碼,若帳密輸入正確,則透過簡訊服務發送一組驗證碼到使用者的手機。
Step 3:實作身分驗證與發送驗證碼的邏輯
驗證身分的邏輯是由 AuthenticationService 負責,程式碼如下:
此類別包含兩個方法:
其中透過簡訊傳送驗證碼的部分是透過另一個類別來處理:SmsService。
Step 4:發送驗證碼
SmsService 類別負責發送簡訊。我讓它實作 ASP.NET Identity 的 IIDentityMessageService 介面,而該介面只有一個方法:SendAsync。程式碼如下:
Twilio 是位於美國的一個通訊服務平台,它提供了很方便的程式呼叫介面,讓開發人員能夠以 HTTP GET/POST 的方式發送簡訊(也能接收簡訊)。我事先已經在 Twilio 網站上註冊了個人的試用帳戶,可以發送簡訊到自己的手機。上列程式碼中,指定給 fromPhone 的電話號碼,就是我的 Twilio 帳戶的電話號碼。
Step 5:讓使用者輸入驗證碼
加入一個新的 Web Form,命名為 CheckAuthToken.aspx。在網頁上放一個 TextBox 讓使用者輸入驗證碼,再放一個確認按鈕。撰寫按鈕的 Click 事件處理常式:
這樣就實作完成一個基本的雙因素驗證機制了。
執行結果
在登入頁面輸入帳號密碼:
點擊【登入】按鈕之後,查看手機的簡訊以取得驗證碼:
接著回到輸入驗證碼的頁面:
收工!
延伸閱讀
Scott Hanselman 前天寫了一篇有關雙因素驗證(two-factor authentication)的文章:Adding Two-Factor authentication to an ASP.NET application,想到自己最近也在專案中實作了雙因素驗證,而發送驗證碼的部分也恰好跟他文章裡的範例一樣是透過 Twilio 發簡訊至手機。
不過,人家是貨真價實的運用 ASP.NET Identity 2.0,我這裡的範例不過就是使用了 IIdentityMessageService 和 IdentityMessage 這兩個型別,充其量只跟 Identity 2.0 沾點邊而已。用來示範雙因素驗證的基本流程以及如何透過 Twilio 服務平台發送簡訊倒是真的。
以下說明實作此範例的步驟。
開發工具:Visual Studio 2013
Step 1. 建立新專案
目標平台:.NET Framework 4.5
專案名稱:TwoFactorAuthDemo
選擇空白專案範本,勾選 Web Forms:
透過 NuGet Manager 加入組件參考:Microsoft.AspNet.Identity.Core 以及 Twilio REST API:
protected void Application_Start(object sender, EventArgs e) { ScriptManager.ScriptResourceMapping.AddDefinition( "jquery", new ScriptResourceDefinition { Path = "~/Scripts/jquery-2.1.0.js" }); }
註:若少了此步驟,網頁執行時會出現錯誤訊息「UnobtrusiveValidationMode requires a ScriptResourceMapping for 'jquery'. Please add a ScriptResourceMapping named jquery(case-sensitive)」
Step 2:建立登入頁面
New 一個 Web Form,取名為 Login.aspx。從 Toolbox 拖拉一個 Login 控制項至網頁上,然後撰寫該控制項的 Authenticate 事件處理函式:
protected void Login1_Authenticate(object sender, AuthenticateEventArgs e) { var authService = new Services.AuthenticationService(); if (authService.AuthenticateAndSendToken(Login1.UserName, Login1.Password).Result) { e.Authenticated = true; Response.Redirect("CheckAuthToken.aspx"); } else { e.Authenticated = false; Response.Write("帳號密碼驗證失敗!"); } }
我把身分驗證的邏輯寫在 Services 資料夾下的 AuthenticationService 類別裡,該類別的 AuthenticateAndSendToken 方法會負責檢查帳號密碼,若帳密輸入正確,則透過簡訊服務發送一組驗證碼到使用者的手機。
Step 3:實作身分驗證與發送驗證碼的邏輯
驗證身分的邏輯是由 AuthenticationService 負責,程式碼如下:
using Microsoft.AspNet.Identity; using System.Threading.Tasks; namespace TwoFactorAuthDemo.Services { public class AuthenticationService { public async Task<bool> AuthenticateAndSendToken(string userId, string password) { if (userId == "michael" && password == "1234") { // 透過 User DAO 取得使用者資訊(目的是取得手機號碼) string userPhone = "+88693668XXXX"; // 產生隨機驗證碼,儲存於資料庫中,並且設定其有效期限(例如五分鐘) string authToken = "9999"; // 準備發送驗證碼的訊息 var idMsg = new IdentityMessage() { Body = "您的登入驗證碼是: " + authToken, Destination = userPhone // 註:若是透過 e-mail 發送驗證碼則還需要設定 Subject 屬性. }; // 發送驗證碼 var smsService = new SmsService(); await smsService.SendAsync(idMsg); return true; } return false; } public bool CheckToken(string userId, string token) { // 從資料庫中取出此 userId 的二階段驗證碼,並檢查是否已過期或已經驗證過. string authToken = "9999"; return (token == authToken); } } }
此類別包含兩個方法:
- AuthenticateAndSendToken-檢查帳號密碼,並且發送一組驗證碼至使用者的手機。
- CheckToken-檢查驗證碼是否正確。這個方法稍後會用到。
其中透過簡訊傳送驗證碼的部分是透過另一個類別來處理:SmsService。
Step 4:發送驗證碼
SmsService 類別負責發送簡訊。我讓它實作 ASP.NET Identity 的 IIDentityMessageService 介面,而該介面只有一個方法:SendAsync。程式碼如下:
using Microsoft.AspNet.Identity; using System; using System.Threading.Tasks; using Twilio; namespace TwoFactorAuthDemo.Services { public class SmsService : IIdentityMessageService { public Task SendAsync(IdentityMessage message) { string twilioAccountSid = "AC060000111122223333444455551af92"; string twilioAccountToken = "94639-這應該只有你自己知道-f3cd06"; string fromPhone = "+13478972288"; string toPhone = message.Destination; var twilio = new TwilioRestClient(twilioAccountSid, twilioAccountToken); var msg = twilio.SendMessage(fromPhone, toPhone, message.Body); if (String.IsNullOrEmpty(msg.Sid) == false) { return Task.FromResult(false); } return Task.FromResult(true); } } }
Twilio 是位於美國的一個通訊服務平台,它提供了很方便的程式呼叫介面,讓開發人員能夠以 HTTP GET/POST 的方式發送簡訊(也能接收簡訊)。我事先已經在 Twilio 網站上註冊了個人的試用帳戶,可以發送簡訊到自己的手機。上列程式碼中,指定給 fromPhone 的電話號碼,就是我的 Twilio 帳戶的電話號碼。
Step 5:讓使用者輸入驗證碼
加入一個新的 Web Form,命名為 CheckAuthToken.aspx。在網頁上放一個 TextBox 讓使用者輸入驗證碼,再放一個確認按鈕。撰寫按鈕的 Click 事件處理常式:
protected void btnOk_Click(object sender, EventArgs e) { var svc = new Services.AuthenticationService(); if (svc.CheckToken("michael", txtAuthCode.Text)) { Response.Write("登入成功!"); } else { Response.Write("登入失敗! 請重新輸入,或發送新的驗證碼。"); } }
這樣就實作完成一個基本的雙因素驗證機制了。
執行結果
在登入頁面輸入帳號密碼:
點擊【登入】按鈕之後,查看手機的簡訊以取得驗證碼:
接著回到輸入驗證碼的頁面:
收工!
延伸閱讀
沒有留言: