VS2013中web項目中自動生成的ASP.NET Identity代碼思考


vs2013沒有再分webform、mvc、api項目,使用vs2013創建一個web項目模板選MVC,身份驗證選個人用戶賬戶。項目會生成ASP.NET Identity的一些代碼。這些代碼主要在AccountController中。

ASP.NET Identity微軟宣稱的好處就不說了,這是原文

ASP.NET Identity

As the membership story in ASP.NET has evolved over the years, the ASP.NET team has learned a lot from feedback from customers.

The assumption that users will log in by entering a user name and password that they have registered in your own application is no longer valid. The web has become more social. Users are interacting with each other in real time through social channels such as Facebook, Twitter, and other social web sites. Developers want users to be able to log in with their social identities so that they can have a rich experience on their web sites. A modern membership system must enable redirection-based log-ins to authentication providers such as Facebook, Twitter, and others.

As web development evolved, so did the patterns of web development. Unit testing of application code became a core concern for application developers. In 2008 ASP.NET added a new framework based on the Model-View-Controller (MVC) pattern, in part to help developers build unit testable ASP.NET applications. Developers who wanted to unit test their application logic also wanted to be able to do that with the membership system.

Considering these changes in web application development, ASP.NET Identity was developed with the following goals:
• One ASP.NET Identity system •ASP.NET Identity can be used with all of the ASP.NET frameworks, such as ASP.NET MVC, Web Forms, Web Pages, Web API, and SignalR.
• ASP.NET Identity can be used when you are building web, phone, store, or hybrid applications. 

• Ease of plugging in profile data about the user •You have control over the schema of user and profile information. For example, you can easily enable the system to store birth dates entered by users when they register an account in your application.
 Persistence control •By default, the ASP.NET Identity system stores all the user information in a database. ASP.NET Identity uses Entity Framework Code First to implement all of its persistence mechanism.
•Since you control the database schema, common tasks such as changing table names or changing the data type of primary keys is simple to do.
•It's easy to plug in different storage mechanisms such as SharePoint, Windows Azure Storage Table Service, NoSQL databases, etc., without having to throw System.NotImplementedExceptions exceptions.

• Unit testability • ASP.NET Identity makes the web application more unit testable. You can write unit tests for the parts of your application that use ASP.NET Identity.

• Role provider • There is a role provider which lets you restrict access to parts of your application by roles. You can easily create roles such as “Admin” and add users to roles.

• Claims Based • ASP.NET Identity supports claims-based authentication, where the user’s identity is represented as a set of claims. Claims allow developers to be a lot more expressive in describing a user’s identity than roles allow. Whereas role membership is just a boolean (member or non-member), a claim can include rich information about the user’s identity and membership.

•Social Login Providers • You can easily add social log-ins such as Microsoft Account, Facebook, Twitter, Google, and others to your application, and store the user-specific data in your application.

• Windows Azure Active Directory •You can also add log-in functionality using Windows Azure Active Directory, and store the user-specific data in your application. For more information, see  Organizational Accounts in Creating ASP.NET Web Projects in Visual Studio 2013

• OWIN Integration • ASP.NET authentication is now based on OWIN middleware that can be used on any OWIN-based host. ASP.NET Identity does not have any dependency on System.Web. It is a fully compliant OWIN framework and can be used in any OWIN hosted application.
•ASP.NET Identity uses OWIN Authentication for log-in/log-out of users in the web site. This means that instead of using FormsAuthentication to generate the cookie, the application uses OWIN CookieAuthentication to do that.

• NuGet package • ASP.NET Identity is redistributed as a NuGet package which is installed in the ASP.NET MVC, Web Forms and Web API templates that ship with Visual Studio 2013. You can download this NuGet package from the NuGet gallery.
•Releasing ASP.NET Identity as a NuGet package makes it easier for the ASP.NET team to iterate on new features and bug fixes, and deliver these to developers in an agile manner.

 

我的感興趣的主要是幾個方面。1、可以擴展用戶類的字段;2、使用EF codefirst存儲;3、OWIN集成 。4、基於Claims(Claims是什么,到底有什么用我都不知道,只知道是.NET框架里的一個命名空間)。

我看了整個代碼覺得它有點類似於三層架構。這里要特別重要的幾個類:

  • ApplicationDbContext類。就是繼承字自ef的DbContext,EF codefirst的必備。
  • UserStore類。封裝了數據庫訪問一系列方法,通過DbContext操作數據庫。類似三層架構中的數據訪問層。
  • UserManager類。用戶管理的類,封裝了用戶、角色、Claim等一系列的方法,通過UserStore類與數據庫交互。類似三層的業務邏輯層。
  • AuthenticationManager類。Owin的一些東西,包含了用戶登錄、注銷、驗證等一些方法。
  • ApplicationUser。用戶模型。繼承自IdentityUser,可以自行擴展屬性

這個東西怎么用呢:

一、設置ApplicationDbContext類

先看下代碼:

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
    {
        public ApplicationDbContext()
            : base("DefaultConnection")
        {
        }
    }

這個類繼承自IdentityDbContext類,ApplicationUser是用戶模型。

這里要設置的就是base("DefaultConnection")。數據庫的鏈接字符串。在web.config的connectionStrings節設置。

image

我們再分析IdentityDbContext類的元數據。

image

可以看出它繼承自DbContext。共再數據庫創建兩個表,Users根據傳輸的用戶模型來創建。角色表 Roles表根據IdentityRole來創建(這個類只有兩個屬性ID和name)看以看出這里角色的字段是不能擴展的。

二、擴展用戶模型(ApplicationUser)

當然不擴展可以直接用,當預設不滿足要求時就可以自行擴展字段。首先看下代碼

// You can add profile data for the user by adding more properties to your ApplicationUser class, please visit http://go.microsoft.com/fwlink/?LinkID=317594 to learn more.
    public class ApplicationUser : IdentityUser
    {
    }

是個繼承自IdentityUser的空類,需要擴展的字段直接寫這就行,如果擴展個年齡(Age)

// You can add profile data for the user by adding more properties to your ApplicationUser class, please visit http://go.microsoft.com/fwlink/?LinkID=317594 to learn more.
    public class ApplicationUser : IdentityUser
    {
        public int Age { get; set; }
    }

我們看下其繼承的IdentityUser類,這里面都是一些預知的屬性。IUser是一個接口只有ID和username兩個屬性。

public class IdentityUser : IUser
    {
        public IdentityUser();
        public IdentityUser(string userName);

        public virtual ICollection<IdentityUserClaim> Claims { get; }
        public virtual string Id { get; set; }
        public virtual ICollection<IdentityUserLogin> Logins { get; }
        public virtual string PasswordHash { get; set; }
        public virtual ICollection<IdentityUserRole> Roles { get; }
        public virtual string SecurityStamp { get; set; }
        public virtual string UserName { get; set; }
    }

三、利用UserManager,AuthenticationManager進行用戶相關操作

這一步就可直接在控制器中寫代碼了。我們先看下AccountController的構造函數

[Authorize]
    public class AccountController : Controller
    {
        public AccountController()
            : this(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext())))
        {
        }

注意,UserManager,ApplicationUser,UserStore,ApplicationDbContext

1、看下用戶注冊代碼

[HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public async Task<ActionResult> Register(RegisterViewModel model)
        {
            if (ModelState.IsValid)
            {
                var user = new ApplicationUser() { UserName = model.UserName };
                var result = await UserManager.CreateAsync(user, model.Password);
                if (result.Succeeded)
                {
                    await SignInAsync(user, isPersistent: false);
                    return RedirectToAction("Index", "Home");
                }
                else
                {
                    AddErrors(result);//一個循環向ModelState添加錯誤消息的方法
                }
            }

            // 如果我們進行到這一步時某個地方出錯,則重新顯示表單
            return View(model);
        }

我們來看下這段代碼。

public async Task<ActionResult> Register(RegisterViewModel model)這句將Register聲明為異步action。

var user = new ApplicationUser() { UserName = model.UserName };這句是ApplicationUser這個創建模型類。

var result = await UserManager.CreateAsync(user, model.Password);
這句是一個異步添加用戶。利用UserManager這個類的CreateAsync方法創建用戶。

類元數據如下圖,里面封裝了各種用戶操作的方法。

image

await SignInAsync(user, isPersistent: false);這句依然。這里是AccountController的一個函數,代碼如下:

private async Task SignInAsync(ApplicationUser user, bool isPersistent)
        {
            AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
            var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
            AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
        }

可以看出利用AuthenticationManager的SignOut和SignIn進行清除cookie和登錄。

2、再看下注銷

[HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult LogOff()
        {
            AuthenticationManager.SignOut();
            return RedirectToAction("Index", "Home");
        }

使用AuthenticationManager.SignOut方法。這是類似於 WebFor中的FormsAuthentication所使用的FormsAuthentication.SignOut方法。

3、再看登錄代碼

[HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
        {
            if (ModelState.IsValid)
            {
                var user = await UserManager.FindAsync(model.UserName, model.Password);
                if (user != null)
                {
                    await SignInAsync(user, model.RememberMe);
                    return RedirectToLocal(returnUrl);
                }
                else
                {
                    ModelState.AddModelError("", "Invalid username or password.");
                }
            }

            // 如果我們進行到這一步時某個地方出錯,則重新顯示表單
            return View(model);
        }

代碼比較類似,用UserManagerFindAsync查找用戶,成功又有是用調用SignInAsync方法進行登錄(方法內部是用AuthenticationManager的SignIn進行登錄)

四、總結

這里用到的是ApplicationDbContext、UserStore、UserManager、AuthenticationManager、ApplicationUser這5個類。其中ApplicationDbContext需要設置連接字符串,ApplicationUser可以擴展用戶字段,UserStore、UserManager、AuthenticationManager這三個類都封裝好的類直接拿來用就行,關鍵是要理解方法和屬性的含義、清楚其用途。

五、問題及思考

  • 依靠[Authorize]應該是用來驗證用戶是否登錄的,直接用來進行權限管理(控制器上寫[Authorize(Roles="管理員")])是不是太僵化了?
  • Claims這是東西什么東西,從來沒用過,是否與權限有關?


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM