1. 程式人生 > 其它 >VS2013中web專案中自動生成的ASP.NET Identity程式碼思考

VS2013中web專案中自動生成的ASP.NET Identity程式碼思考

引用:https://www.cnblogs.com/mzwhj/p/3540017.html

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節設定。

我們再分析IdentityDbContext類的元資料。

可以看出它繼承自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方法建立使用者。

類元資料如下圖,裡面封裝了各種使用者操作的方法。

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);
        }

程式碼比較類似,用UserManager的FindAsync查詢使用者,成功又有是用呼叫SignInAsync方法進行登入(方法內部是用AuthenticationManager的SignIn進行登入)

四、總結

這裡用到的是ApplicationDbContext、UserStore、UserManager、AuthenticationManager、ApplicationUser這5個類。其中ApplicationDbContext需要設定連線字串,ApplicationUser可以擴充套件使用者欄位,UserStore、UserManager、AuthenticationManager這三個類都封裝好的類直接拿來用就行,關鍵是要理解方法和屬性的含義、清楚其用途。

五、問題及思考

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

引用:https://www.cnblogs.com/mzwhj/p/3540017.html

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節設定。

我們再分析IdentityDbContext類的元資料。

可以看出它繼承自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方法建立使用者。

類元資料如下圖,裡面封裝了各種使用者操作的方法。

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);
        }

程式碼比較類似,用UserManager的FindAsync查詢使用者,成功又有是用呼叫SignInAsync方法進行登入(方法內部是用AuthenticationManager的SignIn進行登入)

四、總結

這裡用到的是ApplicationDbContext、UserStore、UserManager、AuthenticationManager、ApplicationUser這5個類。其中ApplicationDbContext需要設定連線字串,ApplicationUser可以擴充套件使用者欄位,UserStore、UserManager、AuthenticationManager這三個類都封裝好的類直接拿來用就行,關鍵是要理解方法和屬性的含義、清楚其用途。

五、問題及思考

  • 依靠[Authorize]應該是用來驗證使用者是否登入的,直接用來進行許可權管理(控制器上寫[Authorize(Roles="管理員")])是不是太僵化了?
  • Claims這是東西什麼東西,從來沒用過,是否與許可權有關?
作者:洞庭夕照
出處:http://mzwhj.cnblogs.com
本文由洞庭夕照原創,併發布到部落格園,歡迎轉載,但必須在文章頁面明顯位置寫明作者和出處,非常感謝!
公眾號: