摘要:第八次當選 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("登入失敗! 請重新輸入,或發送新的驗證碼。");
}
}
這樣就實作完成一個基本的雙因素驗證機制了。
執行結果
在登入頁面輸入帳號密碼:
點擊【登入】按鈕之後,查看手機的簡訊以取得驗證碼:
接著回到輸入驗證碼的頁面:
收工!
延伸閱讀






沒有留言: