1. 程式人生 > >開始使用ASP.NET Identity,初級篇

開始使用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 資料庫。但是現在,對於 Web 應用程式的資料儲存我們有了更多的選擇。而且,大多數開發者希望自己的站點能夠使用第三方供應商提供的社交賬號來實現身份驗證和授權。但是,由於 ASP.NET Membership自身設計的限制,已經難以滿足如下變化:

  • 資料庫架構為 SQL Server 設計,而且無法修改。雖然你可以新增額外的使用者資訊,但這些資料被存入了一張不同的資料表。而且這些資訊難以訪問,除了使用 Profile Provider API
  • 雖然通過Provider,你可以對後臺資料儲存結構的修改,但是該Provider的設計是假設我們對關係型資料庫進行修改。雖然你也可以寫一個面向非關係型(例如
     Windows Azure Tables)儲存機制的Provider。但是,圍繞著相關的設計,你還需要大量的工作。這包括編寫大量的程式碼,以及為那些 NoSQL 資料庫不支援的方法丟擲一大堆 System.NotImplementedException 異常。
  • 由於登入、登出功能基於表單身份驗證,因此ASP.NET Membership 無法支援 OWINOWIN 包括了一些用於身份驗證的 Middleware 中介軟體,如支援Microsoft 賬戶、 Facebook,GoogleTwitter 等的登入,還支援來自於組織內部的賬號例如 Active Directory  Windows Azure Active Directory 
    等登入。OWIN 也提供了包括對OAuth 2.0, JWT CORS的支援。

正是由於ASP.NET Membership 諸多限制,微軟採取了一系列的補救措施,比如釋出了ASP.NET Simple Membership ASP.NET Universal Providers,他們通過Entity FrameworkCode 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 FormsWeb PagesASP.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,TwitterGoogle 等),並將使用者特定的資料存入你的應用程式。

    Windows Azure Active Directory

  • 你還可以加入使用 Windows Azure Active Directory 進行登入的功能,並將使用者特定的資料存入你的應用程式。

    OWIN 整合

  • ASP.NET 身份驗證現在是基於 OWIN 中介軟體實現,並且可以在任何基於 OWIN 的宿主上使用。ASP.NET Identity 不依賴System.Web程式集,與此同時,它完全兼容於 OWIN 框架,並且能被用在任何基於OWIN HostServer 之上。
  • ASP.NET Identity使用OWIN Authentication來登入、登出操作。這意味著應用程式使用CookieAuthentication 生成 cookie 而非FormsAuthentication 

    NuGet 

  • ASP.NET Identity 作為一個 NuGet 包進行釋出,並且安裝在ASP.NET MVCWeb Forms  ASP.NET Web API 專案模板中。當然,你也可以從 NuGet 庫中下載它。
  • ASP.NET IdentityNuGet包的形式釋出,這樣能讓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
  1. <connectionStrings>
  2.   <add name="IdentityDb" providerName="System.Data.SqlClient"
  3.        connectionString="Data Source=(localdb)\v11.0;Initial Catalog=IdentityDb;Integrated Security=True;Connect Timeout=15;Encrypt=False;TrustServerCertificate=False; MultipleActiveResultSets=True" />
  4. </connectionStrings>
  5. <appSettings>
  6.   <add key="owin:AppStartup" value="UsersManagement.IdentityConfig" />
  7. </appSettings>

建立Entity Framework 

如果大家使用過ASP.NET Membership,對比過後你會發現在ASP.NET Identity擴充套件User資訊是多麼的簡單和方便。

1.建立 User 類

第一個要被建立的類它代表使用者,我將它命名為AppUser,繼承自Microsoft.AspNet.Identity.EntityFramework 名稱空間下IdentityUser,IdentityUser 提供了基本的使用者資訊,如Email、PasswordHash、UserName、PhoneNumber、Roles等,當然我們也可以在其派生類中新增額外的資訊,程式碼如下:

  1. using Microsoft.AspNet.Identity.EntityFramework;
  2. namespace UsersManagement.Models
  3. {
  4.     public class AppUser:IdentityUser
  5.     {
  6.     }
  7. }

2.建立 Database Context 類

接下來的步驟就是建立EF Database Context 來操作AppUser。ASP.NET Identity將使用Code First 來建立和管理資料庫架構。值得注意的是,Database Context必須繼承自IdentityDbContext<T>,而且T為User類(在此示例即AppUser),程式碼如下所示:

  1. public class AppIdentityDbContext : IdentityDbContext<AppUser>
  2.    {
  3.        public AppIdentityDbContext() : base("IdentityDb")
  4.        {
  5.        }
  6.        static AppIdentityDbContext()
  7.        {
  8.            Database.SetInitializer<AppIdentityDbContext>(new IdentityDbInit());
  9.        }
  10.        public static AppIdentityDbContext Create()
  11.        {
  12.            return new AppIdentityDbContext();
  13.        }
  14.    }
  15.    public class IdentityDbInit : DropCreateDatabaseIfModelChanges<AppIdentityDbContext>
  16.    {
  17.        protected override void Seed(AppIdentityDbContext context)
  18.        {
  19.            PerformInitialSetup(context);
  20.            base.Seed(context);
  21.        }
  22.        public void PerformInitialSetup(AppIdentityDbContext context)
  23.        {
  24.            //初始
  25.        }
  26.    }

上述程式碼中,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中操作使用者的方法。程式碼如下所示:

  1. /// <summary>
  2. /// 使用者管
  3. /// </summary>
  4.  public class AppUserManager : UserManager<AppUser> {
  5.      public AppUserManager(IUserStore<AppUser> store)
  6.          : base(store) {
  7.      }
  8.      public static AppUserManager Create(
  9.              IdentityFactoryOptions<AppUserManager> options,
  10.              IOwinContext context) {
  11.          AppIdentityDbContext db = context.Get<AppIdentityDbContext>();
  12.          //UserStore<T> 是 包含在 Microsoft.AspNet.Identity.EntityFramework 中,它實現了 UserManger 類中與使用者操作相關的方法。