開始使用ASP.NET Identity,初級篇
回到頂部在之前的文章中,我為大家介紹了OWIN和Katana,有了對它們的基本瞭解後,才能更好的去學習ASP.NET Identity,因為它已經對OWIN 有了良好的整合。
在這篇文章中,我主要關注ASP.NET Identity的建立和使用,包括基礎類的搭建和使用者管理功能的實現——
在後續文章中,我將探索它更高階的用法,比如身份驗證並聯合ASP.NET MVC 進行授權、使用第三方登入、宣告式認證等。
ASP.NET Identity 前世今生
ASP.NET Membership
在ASP.NET 2.0時代,ASP.NET Membership用於使用者管理的常見需求。包括表單身份驗證(Form Authentication
- 資料庫架構為 SQL Server 設計,而且無法修改。雖然你可以新增額外的使用者資訊,但這些資料被存入了一張不同的資料表。而且這些資訊難以訪問,除了使用 Profile Provider API。
- 雖然通過Provider,你可以對後臺資料儲存結構的修改,但是該Provider的設計是假設我們對關係型資料庫進行修改。雖然你也可以寫一個面向非關係型(例如
- 由於登入、登出功能基於表單身份驗證,因此ASP.NET Membership 無法支援 OWIN。OWIN 包括了一些用於身份驗證的 Middleware 中介軟體,如支援Microsoft 賬戶、 Facebook,、Google、Twitter 等的登入,還支援來自於組織內部的賬號例如 Active Directory 、 Windows Azure Active Directory
正是由於ASP.NET Membership 諸多限制,微軟採取了一系列的補救措施,比如釋出了ASP.NET Simple Membership 和ASP.NET Universal Providers,他們通過Entity Framework的Code First,可以方便的去擴充套件使用者資訊,而非像ASP.NET Membership 那樣需要Provider 來實現。
但是它們仍舊存在不足,主要包括如下兩點:
- 對非關係型資料庫支援不好
- 無法和OWIN相容
ASP.NET Identity
由於ASP.NET Membership、ASP.NET Simple Membership 、ASP.NET Universal Providers 設計上的不足,微軟在接受了大量反饋後,於.NET Framework 4.5 中推出了ASP.NET Identity,如果用一句話概括——ASP.NET Identity 為ASP.NET 應用程式提供了一系列的API用來管理和維護使用者 ,它包括如下新特性:
• One ASP.NET Identity
- ASP.NET Identity 可以用在所有的 ASP.NET 框架上,例如 ASP.NET MVC, Web Forms,Web Pages,ASP.NET Web API 和SignalR
- ASP.NET Identity 可以用在各種應用程式中,例如Web 應用程式、移動應用、商店應用或者混合架構應用
•易於管理使用者資訊
- ASP.NET Identity提供了豐富的API ,可以方便的管理使用者
•持久化控制
- 預設情況下,ASP.NET Identity將使用者所有的資料儲存在資料庫中。ASP.NET Identity 使用 Entity Framework 實現其所有的檢索和持久化機制。
- 通過Code First,你可以對資料庫架構的完全控制,一些常見的任務例如改變表名稱、改變主鍵資料型別等都可以很輕易地完成。
- 能夠很容易地引入其他不同的儲存機制,例如 SharePoint, Windows Azure 儲存表服務, NoSQL 資料庫等。不必再丟擲 System.NotImplementedException 異常了。
•單元測試能力
- ASP.NET Identity 能讓 Web 應用程式能夠更好地進行單元測試。你可以為你應用程式使用了 ASP.NET Identity 的部分編寫單元測試。
•角色Provider
- ASP.NET Identity 中的角色Provider配合ASP.NET MVC Authorize,可以讓你基於角色來限制對應用程式某個部分的訪問。你可以很容易地建立Admin之類的角色,並將使用者加入其中。
•基於宣告的
- ASP.NET Identity 支援基於宣告的身份驗證,它使用一組"宣告"來表示使用者的身份標識。相對於"角色","宣告"能使開發人員能夠更好地描述使用者的身份標識。"角色"本質上只是一個布林型別(即"屬於"或"不屬於"特定角色),而一個"宣告"可以包含更多關於使用者標識和成員資格的資訊。
•社交賬號登入Provider
- 你可以很容易的為你的應用程式加入社交賬號登入功能(例如 Microsoft 賬戶,Facebook,,Twitter,Google 等),並將使用者特定的資料存入你的應用程式。
• Windows Azure Active Directory
- 你還可以加入使用 Windows Azure Active Directory 進行登入的功能,並將使用者特定的資料存入你的應用程式。
• OWIN 整合
- ASP.NET 身份驗證現在是基於 OWIN 中介軟體實現,並且可以在任何基於 OWIN 的宿主上使用。ASP.NET Identity 不依賴System.Web程式集,與此同時,它完全兼容於 OWIN 框架,並且能被用在任何基於OWIN 的Host和Server 之上。
- ASP.NET Identity使用OWIN Authentication來登入、登出操作。這意味著應用程式使用CookieAuthentication 生成 cookie 而非FormsAuthentication 。
• NuGet 包
- ASP.NET Identity 作為一個 NuGet 包進行釋出,並且安裝在ASP.NET MVC,Web Forms 和 ASP.NET Web API 專案模板中。當然,你也可以從 NuGet 庫中下載它。
- ASP.NET Identity以NuGet包的形式釋出,這樣能讓ASP.NET 團隊更好的Bug修復和迭代新功能,與此同時,開發人員可以在第一時間獲取到最新版本。
建立 ASP.NET Identity
建立 ASP.NET Identity資料庫
ASP.NET Identity並不像ASP.NET Membership那樣依賴SQL Server架構,但關係型儲存仍然是預設和最簡單的實現方式,儘管近些年來NoSQL發展迅猛,但關係型資料庫易於理解,仍舊是開發團隊內部主流的儲存選擇。
ASP.NET Identity使用Entity Framework Code First來自動建立資料庫架構。在此示例中,我使用localdb來建立一個空的資料庫IdentityDb,然後交由Code First管理資料庫架構。
localdb內建在Visual Studio中而且它是輕量級的SQL Server,能讓開發者簡單快速操作資料庫。
新增ASP.NET Identity 包
Identity以包的形式釋出在NuGet上,這能夠很方便的將它安裝到任意專案中,通過在Package Manger Console輸入如下命令來安裝Identity:
- Install-Package Microsoft.AspNet.Identity.EntityFramework
- Install-Package Microsoft.AspNet.Identity.OWIN
- Install-Package Microsoft.Owin.Host.SystemWeb
在 Visual Studio中選擇建立一個完整的ASP.NET MVC專案時,預設情況下該模板會使用ASP.NET Identity API自動新增通用的使用者管理模組。對於初學者,我建議學習它裡面API的使用,但我不推薦將它使用在正式環境中,因為它產生了過多的通用和冗餘程式碼,有時候我們只想讓它簡單工作。
更新Web.config檔案
若要將ASP.NET Identity使用在專案裡,除了新增相應的包之外,還需要在Web.config中新增如下配置資訊:
- 資料庫連線字串
- 指定的OWIN Startup啟動項,用作初始化Middleware至Pipeline
- <connectionStrings>
- <add name="IdentityDb" providerName="System.Data.SqlClient"
- connectionString="Data Source=(localdb)\v11.0;Initial Catalog=IdentityDb;Integrated Security=True;Connect Timeout=15;Encrypt=False;TrustServerCertificate=False; MultipleActiveResultSets=True" />
- </connectionStrings>
- <appSettings>
- <add key="owin:AppStartup" value="UsersManagement.IdentityConfig" />
- </appSettings>
建立Entity Framework 類
如果大家使用過ASP.NET Membership,對比過後你會發現在ASP.NET Identity擴充套件User資訊是多麼的簡單和方便。
1.建立 User 類
第一個要被建立的類它代表使用者,我將它命名為AppUser,繼承自Microsoft.AspNet.Identity.EntityFramework 名稱空間下IdentityUser,IdentityUser 提供了基本的使用者資訊,如Email、PasswordHash、UserName、PhoneNumber、Roles等,當然我們也可以在其派生類中新增額外的資訊,程式碼如下:
- using Microsoft.AspNet.Identity.EntityFramework;
- namespace UsersManagement.Models
- {
- public class AppUser:IdentityUser
- {
- }
- }
2.建立 Database Context 類
接下來的步驟就是建立EF Database Context 來操作AppUser。ASP.NET Identity將使用Code First 來建立和管理資料庫架構。值得注意的是,Database Context必須繼承自IdentityDbContext<T>,而且T為User類(在此示例即AppUser),程式碼如下所示:
- public class AppIdentityDbContext : IdentityDbContext<AppUser>
- {
- public AppIdentityDbContext() : base("IdentityDb")
- {
- }
- static AppIdentityDbContext()
- {
- Database.SetInitializer<AppIdentityDbContext>(new IdentityDbInit());
- }
- public static AppIdentityDbContext Create()
- {
- return new AppIdentityDbContext();
- }
- }
- public class IdentityDbInit : DropCreateDatabaseIfModelChanges<AppIdentityDbContext>
- {
- protected override void Seed(AppIdentityDbContext context)
- {
- PerformInitialSetup(context);
- base.Seed(context);
- }
- public void PerformInitialSetup(AppIdentityDbContext context)
- {
- //初始化
- }
- }
上述程式碼中,AppIdentityDbContext 的建構函式呼叫基類建構函式並將資料庫連線字串的Name作為引數傳遞,它將用作連線資料庫。同時,當Entity Framework Code First成功建立資料庫架構後,AppIdentityDbContext的靜態建構函式呼叫Database.SetInitializer方法Seed 資料庫而且只執行一次。在這兒,我的Seed 類IdentityDbInit。
最後,AppIdentityDbContext 定義了 Create方法,它將被 OWIN Middleware回掉然後返回AppIdentityDbContext例項,這個例項被儲存在OwinContext中。
3.建立User Manger 類
User Manager類作為ASP.NET Identity中最為重要的類之一,用來管理User。同樣,自定義的User Manger類必須繼承自UserManager<T >,此處T就為AppUser。UserManager<T>提供了建立和操作使用者的一些基本方法並且全面支援C# 非同步程式設計,所以你可以使用CreateAsync(Create),FindAsync(Find)、DeleteAsync(Delete)、UpdateAsync(Update)來進行使用者管理,值得注意的是,它並不通過Entity Framework 來直接操作使用者,而是間接呼叫UserStore來實現。UserStore<T>是Entity Framework 類並實現了IUserStore<T>介面,並且實現了定義在UserManger中操作使用者的方法。程式碼如下所示:
- /// <summary>
- /// 使用者管理
- /// </summary>
- public class AppUserManager : UserManager<AppUser> {
- public AppUserManager(IUserStore<AppUser> store)
- : base(store) {
- }
- public static AppUserManager Create(
- IdentityFactoryOptions<AppUserManager> options,
- IOwinContext context) {
- AppIdentityDbContext db = context.Get<AppIdentityDbContext>();
- //UserStore<T> 是 包含在 Microsoft.AspNet.Identity.EntityFramework 中,它實現了 UserManger 類中與使用者操作相關的方法。