麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 學院 > 開發設計 > 正文

【ASP.NETIdentity系列教程(二)】運用ASP.NETIdentity

2019-11-14 14:15:03
字體:
來源:轉載
供稿:網友

注:本文是【asp.net Identity系列教程】的第二篇。本系列教程詳細、完整、深入地介紹了微軟的ASP.NET Identity技術,描述了如何運用ASP.NET Identity實現應用程序的用戶管理,以及實現應用程序的認證與授權等相關技術,譯者希望本系列教程能成為掌握ASP.NET Identity技術的一份完整而有價值的資料。讀者若是能夠按照文章的描述,一邊閱讀、一邊實踐、一邊理解,定能有意想不到的巨大收獲!希望本系列博文能夠得到廣大園友的高度推薦。

14 Applying ASP.NET Identity
14 運用ASP.NET Identity

In this chapter, I show you how to apply ASP.NET Identity to authenticate and authorize the user accounts created in the PRevious chapter. I explain how the ASP.NET platform provides a foundation for authenticating requests and how ASP.NET Identity fits into that foundation to authenticate users and enforce authorization through roles. Table 14-1 summarizes this chapter.
本章將演示如何將ASP.NET Identity用于對上一章中創建的用戶賬號進行認證與授權。我將解釋ASP.NET平臺對請求進行認證的基礎,并解釋ASP.NET Identity如何融入這種基礎對用戶進行認證,以及通過角色增強授權功能。表14-1描述了本章概要。

Table 14-1. Chapter Summary
表14-1. 本章概要
Problem
問題
Solution
解決方案
Listing
清單號
Prepare an application for user authentication.
準備用戶認證的應用程序
Apply the Authorize attribute to restrict access to action methods and define a controller to which users will be redirected to provide credentials.
運用Authorize注解屬性來限制對動作方法的訪問,并定義一個對用戶重定向的控制器,以便讓用戶提供憑據
1–4
Authenticate a user.
認證用戶
Check the name and passWord using the FindAsync method defined by the user manager class and create an implementation of the IIdentity interface using the CreateIdentityMethod. Set an authentication cookie for subsequent requests by calling the SignIn method defined by the authentication manager class.
使用由用戶管理器類定義的FindAsync方法檢查用戶名和口令,并使用CreateIdentityMethod創建一個IIdentity接口的實現。通過調用由認證管理器類定義的SignIn方法,設置后繼請求的認證Cookie。
5
Prepare an application for role-based authorization.
準備基于角色授權的應用程序
Create a role manager class and register it for instantiation in the OWIN startup class.
創建一個角色管理器類,將其注冊為OWIN啟動類中的實例化
6–8
Create and delete roles.
創建和刪除角色
Use the CreateAsync and DeleteAsync methods defined by the role manager class.
使用由角色管理器類定義的CreateAsyncDeleteAsync方法。
9–12
Manage role membership.
管理角色成員
Use the AddToRoleAsync and RemoveFromRoleAsync methods defined by the user manager class.
使用由用戶管理器類定義的AddToRoleAsyncRemoveFromRoleAsync方法
13–15
Use roles for authorization.
使用角色進行授權
Set the Roles property of the Authorize attribute.
設置Authorize注解屬性的Roles屬性
16–19
Seed the database with initial content.
將初始化內容植入數據庫
Use the database context initialization class.
使用數據庫上下文的初始化類
20, 21

14.1 Preparing the Example Project
14.1 準備示例項目

In this chapter, I am going to continue working on the Users project I created in Chapter 13. No changes to the application components are required.
在本章中,我打算繼續沿用第13章所創建的Users項目,不需要修改該應用程序的組件

14.2 Authenticating Users
14.2 認證用戶

The most fundamental activity for ASP.NET Identity is to authenticate users, and in this section, I explain and demonstrate how this is done. Table 14-2 puts authentication into context.
ASP.NET Identity最基本的活動就是認證用戶,在本小節中,我將解釋并演示其做法。表14-2描述了認證的情形。

Table 14-2. Putting Authentication in Context
表14-2. 認證情形
Question
問題
Answer
回答
What is it?
什么是認證?
Authentication validates credentials provided by users. Once the user is authenticated, requests that originate from the browser contain a cookie that represents the user identity.
認證是驗證用戶提供的憑據。一旦用戶已被認證,源自該瀏覽器的請求便會含有表示該用戶標識的Cookie。
Why should I care?
為何要關心它?
Authentication is how you check the identity of your users and is the first step toward restricting access to sensitive parts of the application.
認證是你檢查用戶標識的辦法,也是限制對應用程序敏感部分進行訪問的第一步。
How is it used by the MVC framework?
如何在MVC框架中使用它?
Authentication features are accessed through the Authorize attribute, which is applied to controllers and action methods in order to restrict access to authenticated users.
認證特性是通過Authorize注解屬性進行訪問的,將該注解屬性運用于控制器和動作方法,目的是將訪問限制到已認證用戶。

Tip I use names and passwords stored in the ASP.NET Identity database in this chapter. In Chapter 15, I demonstrate how ASP.NET Identity can be used to authenticate users with a service from Google (Identity also supports authentication for Microsoft, Facebook, and Twitter accounts).
提示:本章會使用存儲在ASP.NET Identity數據庫中的用戶名和口令。在第15章中將演示如何將ASP.NET Identity用于認證享有Google服務的用戶(Identity還支持對Microsoft、Facebook以及Twitter賬號的認證)。

14.2.1 Understanding the Authentication/Authorization Process
14.2.1 理解認證/授權過程

The ASP.NET Identity system integrates into the ASP.NET platform, which means you use the standard MVC framework techniques to control access to action methods, such as the Authorize attribute. In this section, I am going to apply basic restrictions to the Index action method in the Home controller and then implement the features that allow users to identify themselves so they can gain access to it. Listing 14-1 shows how I have applied the Authorize attribute to the Home controller.
ASP.NET Identity系統集成到了ASP.NET平臺,這意味著你可以使用標準的MVC框架技術來控制對動作方法的訪問,例如使用Authorize注解屬性。在本小節中,我打算在Home控制中的Index動作方法上運用基本的限制,然后實現讓用戶對自己進行標識,以使他們能夠訪問。清單14-1演示了如何將Authorize注解屬性運用于Home控制器。

Listing 14-1. Securing the Home Controller
清單14-1. 實施Home控制器的安全

using System.Web.Mvc;using System.Collections.Generic;
namespace Users.Controllers {
public class HomeController : Controller {
[Authorize] public ActionResult Index() { Dictionary<string, object> data = new Dictionary<string, object>(); data.Add("Placeholder", "Placeholder"); return View(data); } }}

Using the Authorize attribute in this way is the most general form of authorization and restricts access to the Index action methods to requests that are made by users who have been authenticated by the application.
這種方式使用Authorize注解屬性是授權的最一般形式,它限制了對Index動作方法的訪問,由用戶發送給該動作方法的請求必須是應用程序已認證的用戶。

If you start the application and request a URL that targets the Index action on the Home controller (/Home/Index, /Home, or just /), you will see the error shown by Figure 14-1.
如果啟動應用程序,并請求以Home控制器中Index動作為目標的URL(/Home/Index、/Home/),將會看到如圖14-1所示的錯誤。

圖14-1

Figure 14-1. Requesting a protected URL
圖14-1. 請求一個受保護的URL

The ASP.NET platform provides some useful information about the user through the HttpContext object, which is used by the Authorize attribute to check the status of the current request and see whether the user has been authenticated. The HttpContext.User property returns an implementation of the IPrincipal interface, which is defined in the System.Security.Principal namespace. The IPrincipal interface defines the property and method shown in Table 14-3.
ASP.NET平臺通過HttpContext對象提供一些關于用戶的有用信息,該對象由Authorize注解屬性使用的,以檢查當前請求的狀態,考察用戶是否已被認證。HttpContext.User屬性返回的是IPrincipal接口的實現,該接口是在System.Security.Principal命名空間中定義的。IPrincipal接口定義了如表14-3所示的屬性和方法。

Table 14-3. The Members Defined by the IPrincipal Interface
表14-3. IPrincipal接口所定義的成員
Name
名稱
Description
描述
IdentityReturns an implementation of the IIdentity interface that describes the user associated with the request.
返回IIdentity接口的實現,它描述了與請求相關聯的用戶
IsInRole(role)Returns true if the user is a member of the specified role. See the “Authorizing Users with Roles” section for details of managing authorizations with roles.
如果用戶是指定角色的成員,則返回true。參見“以角色授權用戶”小節,其中描述了以角色進行授權管理的細節

The implementation of IIdentity interface returned by the IPrincipal.Identity property provides some basic, but useful, information about the current user through the properties I have described in Table 14-4.
IPrincipal.Identity屬性返回的IIdentity接口實現通過一些屬性提供了有關當前用戶的一些基本卻有用的信息,表14-4描述了這些屬性。

Table 14-4. The Properties Defined by the IIdentity Interface
表14-4. IIdentity接口定義的屬性
Name
名稱
Description
描述
AuthenticationType Returns a string that describes the mechanism used to authenticate the user
返回一個字符串,描述了用于認證用戶的機制
IsAuthenticated Returns true if the user has been authenticated
如果用戶已被認證,返回true。
Name Returns the name of the current user
返回當前用戶的用戶名

Tip In Chapter 15 I describe the implementation class that ASP.NET Identity uses for the IIdentity interface, which is called ClaimsIdentity.
提示:第15章會描述ASP.NET Identity用于IIdentity接口的實現類,其名稱為ClaimsIdentity。

ASP.NET Identity contains a module that handles the AuthenticateRequest life-cycle event, which I described in Chapter 3, and uses the cookies sent by the browser to establish whether the user has been authenticated. I’ll show you how these cookies are created shortly. If the user is authenticated, the ASP.NET framework module sets the value of the IIdentity.IsAuthenticated property to true and otherwise sets it to false. (I have yet to implement the feature that will allow users to authenticate, which means that the value of the IsAuthenticated property is always false in the example application.)
ASP.NET Identity含有一個處理AuthenticateRequest生命周期事件(第3章曾做過描述)的模塊,并使用瀏覽器發送過來的Cookie確認用戶是否已被認證。我很快會演示如何創建這些Cookie。如果用戶已被認證,此ASP.NET框架模塊便會將IIdentity.IsAuthenticated屬性的值設置為true,否則設置為false。(此刻尚未實現讓用戶進行認證的特性,這意味著在本示例應用程序中,IsAuthenticated屬性的值總是false。)

The Authorize module checks the value of the IsAuthenticated property and, finding that the user isn’t authenticated, sets the result status code to 401 and terminates the request. At this point, the ASP.NET Identity module intercepts the request and redirects the user to the /Account/Login URL. This is the URL that I defined in the IdentityConfig class, which I specified in Chapter 13 as the OWIN startup class, like this:
Authorize模塊檢查IsAuthenticated屬性的值,會發現該用戶是未認證的,于是將結果狀態碼設置為401(未授權),并終止該請求。但在這一點處(這里是ASP.NET Identity在請求生命周期中的切入點——譯者注),ASP.NET Identity模塊會攔截該請求,并將用戶重定向到/Account/Login URL。我在IdentityConfig類中已定義了此URL,IdentityConfig是第13章所指定的OWIN啟動類,如下所示:

using Microsoft.AspNet.Identity;using Microsoft.Owin;using Microsoft.Owin.Security.Cookies;using Owin;using Users.Infrastructure; 
namespace Users { public class IdentityConfig { public void Configuration(IAppBuilder app) {
app.CreatePerOwinContext<AppUserManager>(AppUserManager.Create); app.UseCookieAuthentication(new CookieAuthenticationOptions { AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, LoginPath = new PathString("/Account/Login"), }); } }}

The browser requests the /Account/Login URL, but since it doesn’t correspond to any controller or action in the example project, the server returns a 404 – Not Found response, leading to the error message shown in Figure 14-1.
瀏覽器請求/Account/Login時,但因為示例項目中沒有相應的控制器或動作,于服務器返回了“404 – 未找到”響應,從而導致了如圖14-1所示的錯誤消息。

14.2.2 Preparing to Implement Authentication
14.2.2 實現認證的準備

Even though the request ends in an error message, the request in the previous section illustrates how the ASP.NET Identity system fits into the standard ASP.NET request life cycle. The next step is to implement a controller that will receive requests for the /Account/Login URL and authenticate the user. I started by adding a new model class to the UserViewModels.cs file, as shown in Listing 14-2.
雖然請求終止于一條錯誤消息,但上一小節的請求已勾畫出ASP.NET Identity系統是如何切入標準的ASP.NET請求生命周期的。下一個步驟是實現一個控制器,用它來接收對/Account/Login URL的請求,并認證用戶。我首先在UserViewModels.cs文件中添加了一個模型類,如清單14-2所示。

Listing 14-2. Adding a New Model Class to the UserViewModels.cs File
清單14-2. 在UserViewModels.cs文件中添加一個新的模型類

using System.ComponentModel.DataAnnotations; 
namespace Users.Models {
public class CreateModel { [Required] public string Name { get; set; } [Required] public string Email { get; set; } [Required] public string Password { get; set; } }
public class LoginModel { [Required] public string Name { get; set; } [Required] public string Password { get; set; } }}

The new model has Name and Password properties, both of which are decorated with the Required attribute so that I can use model validation to check that the user has provided values.
新模型具有NamePassword屬性,兩者都用Required注解屬性進行了注釋,以使我能夠使用模型驗證來檢查用戶是否提供了這些屬性的值。

Tip In a real project, I would use client-side validation to check that the user has provided name and password values before submitting the form to the server, but I am going to keep things focused on identity and the server-side functionality in this chapter. See Pro ASP.NET MVC 5 for details of client-side form validation.
提示:在一個實際的項目中,我會在用戶將表單遞交到服務器之前,使用客戶端驗證來檢查用戶已經提供了用戶名和口令的值,但在本章中,我打算把注意力集中在標識和服務器端的功能方面??蛻舳吮韱悟炞C的詳情可參閱Pro ASP.NET MVC 5一書。

I added an Account controller to the project, as shown in Listing 14-3, with Login action methods to collect and process the user’s credentials. I have not implemented the authentication logic in the listing because I am going to define the view and then walk through the process of validating user credentials and signing users into the application.
我在項目中添加了一個Account控制器,如清單14-3所示,其中帶有Login動作方法,用以收集和處理用戶的憑據。該清單尚未實現認證邏輯,因為我打算先定義視圖,然后再實現驗證用戶憑據的過程,并讓用戶簽入應用程序。

Listing 14-3. The Contents of the AccountController.cs File
清單14-3. AccountController.cs文件的內容

using System.Threading.Tasks;using System.Web.Mvc;using Users.Models; 
namespace Users.Controllers {
[Authorize] public class AccountController : Controller {
[AllowAnonymous] public ActionResult Login(string returnUrl) { if (ModelState.IsValid) { } ViewBag.returnUrl = returnUrl; return View(); }
[HttpPost] [AllowAnonymous] [ValidateAntiForgeryToken] public async Task<ActionResult> Login(LoginModel details, string returnUrl) { return View(details); } }}

Even though it doesn’t authenticate users yet, the Account controller contains some useful infrastructure that I want to explain separately from the ASP.NET Identity code that I’ll add to the Login action method shortly.
盡管它此刻尚未認證用戶,但Account控制器已包含了一些有用的基礎結構,我想通過ASP.NET Identity代碼對這些結構分別加以解釋,很快就會在Login動作方法中添加這些代碼。

First, notice that both versions of the Login action method take an argument called returnUrl. When a user requests a restricted URL, they are redirected to the /Account/Login URL with a query string that specifies the URL that the user should be sent back to once they have been authenticated. You can see this if you start the application and request the /Home/Index URL. Your browser will be redirected, like this:
首先要注意Login動作方法有兩個版本,它們都有一個名稱為returnUrl的參數。當用戶請求一個受限的URL時,他們被重定向到/Account/Login URL上,并帶有查詢字符串,該字符串指定了一旦用戶得到認證后將用戶返回的URL,如下所示:

/Account/Login?ReturnUrl=%2FHome%2FIndex

The value of the ReturnUrl query string parameter allows me to redirect the user so that navigating between open and secured parts of the application is a smooth and seamless process.
ReturnUrl查詢字符串參數的值可讓我能夠對用戶進行重定向,使應用程序公開和保密部分之間的導航成為一個平滑無縫的過程。

Next, notice the attributes that I have applied to the Account controller. Controllers that manage user accounts contain functionality that should be available only to authenticated users, such as password reset, for example. To that end, I have applied the Authorize attribute to the controller class and then used the AllowAnonymous attribute on the individual action methods. This restricts action methods to authenticated users by default but allows unauthenticated users to log in to the application.
下一個要注意的是運用于Account控制器的注解屬性。管理用戶賬號的控制器含有只能由已認證用戶才能使用的功能,例如口令重置。為此,我在控制器類上運用了Authorize注解屬性,然后又在個別動作方法上運用了AllowAnonymous注解屬性。這會將這些動作方法默認限制到已認證用戶,但又能允許未認證用戶登錄到應用程序。

Finally, I have applied the ValidateAntiForgeryToken attribute, which works in conjunction with the Html.AntiForgeryToken helper method in the view and guards against cross-site request forgery. Cross-site forgery exploits the trust that your user has for your application and it is especially important to use the helper and attribute for authentication requests.
最后要注意的是,我運用了ValidateAntiForgeryToken注解屬性,該屬性與視圖中的Html.AntiForgeryToken輔助器方法聯合工作,防止Cross-Site Request Forgery(CSRF,跨網站請求偽造)的攻擊。CSRF會利用應用程序對用戶的信任,因此使用這個輔助器和注解屬性對于認證請求是特別重要的。

Tip you can learn more about cross-site request forgery at http://en.wikipedia.org/wiki/Cross-site_request_forgery.
提示:更多關于CSRF的信息,請參閱http://en.wikipedia.org/wiki/Cross-site_request_forgery。

My last preparatory step is to create the view that will be rendered to gather credentials from the user. Listing 14-4 shows the contents of the Views/Account/Login.cshtml file, which I created by right-clicking the Index action method and selecting Add View from the pop-up menu.
最后一項準備步驟是創建一個視圖,用以收集來自于用戶的憑據。清單14-4顯示了Views/Account/Login.cshtml文件的內容,這是通過右擊Index動作方法,然后從彈出菜單選擇“Add View(添加視圖)”而創建的。

Listing 14-4. The Contents of the Login.cshtml File
清單14-4. Login.cshtml文件的內容

@model Users.Models.LoginModel@{ ViewBag.Title = "Login";}<h2>Log In</h2> 
@Html.ValidationSummary()
@using (Html.BeginForm()) { @Html.AntiForgeryToken(); <input type="hidden" name="returnUrl" value="@ViewBag.returnUrl" /> <div class="form-group"> <label>Name</label> @Html.TextBoxFor(x => x.Name, new { @class = "form-control" }) </div> <div class="form-group"> <label>Password</label> @Html.PasswordFor(x => x.Password, new { @class = "form-control" }) </div> <button class="btn btn-primary" type="submit">Log In</button>}

The only notable aspects of this view are using the Html.AntiForgeryToken helper and creating a hidden input element to preserve the returnUrl argument. In all other respects, this is a standard Razor view, but it completes the preparations for authentication and demonstrates the way that unauthenticated requests are intercepted and redirected. To test the new controller, start the application and request the /Home/Index URL. You will be redirected to the /Account/Login URL, as shown in Figure 14-2.
該視圖唯一要注意的方面是使用了Html.AntiForgeryToken輔助器,并創建了一個隱藏的input元素,以保護returnUrl參數。在其他方面,這是一個標準的Razor視圖,但它實現了認證的準備工作,并能演示被攔截且被重定向的未認證請求的情況。為了測試這個新的控制器,啟動應用程序,并請求/Home/Index。你將被重定向到/Account/Login,如圖14-2所示。

圖14-2

Figure 14-2. Prompting the user for authentication credentials
圖14-2. 提示用戶輸入認證憑據

14.2.3 Adding User Authentication
14.2.3 添加用戶認證

Requests for protected URLs are being correctly redirected to the Account controller, but the credentials provided by the user are not yet used for authentication. In Listing 14-5, you can see how I have completed the implementation of the Login action.
發送給受保護URL的請求會被正確地重定向到Account控制器,但由用戶提供的憑據尚未被用于認證。從清單14-5可以看出如何完成Login動作的實現。

Listing 14-5. Adding Authentication to the AccountController.cs File
清單14-5. 在AccountController.cs文件中添加認證

using System.Threading.Tasks;using System.Web.Mvc;using Users.Models;using Microsoft.Owin.Security;using System.Security.Claims;using Microsoft.AspNet.Identity;using Microsoft.AspNet.Identity.Owin;using Users.Infrastructure;using System.Web;
namespace Users.Controllers {
[Authorize] public class AccountController : Controller {
[AllowAnonymous] public ActionResult Login(string returnUrl) { ViewBag.returnUrl = returnUrl; return View(); }
[HttpPost] [AllowAnonymous] [ValidateAntiForgeryToken] public async Task<ActionResult> Login(LoginModel details, string returnUrl) { if (ModelState.IsValid) { AppUser user = await UserManager.FindAsync(details.Name, details.Password); if (user == null) { ModelState.AddModelError("", "Invalid name or password."); } else { ClaimsIdentity ident = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie); AuthManager.SignOut(); AuthManager.SignIn(new AuthenticationProperties { IsPersistent = false}, ident); return Redirect(returnUrl); } } ViewBag.returnUrl = returnUrl; return View(details); }
private IAuthenticationManager AuthManager { get { return HttpContext.GetOwinContext().Authentication; } } private AppUserManager UserManager { get { return HttpContext.GetOwinContext().GetUserManager<AppUserManager>(); } } }}

The simplest part is checking the credentials, which I do through the FindAsync method of the AppUserManager class, which you will remember as the user manager class from Chapter 13:
最簡單的部分是檢查憑據,這是通過AppUserManager類的FindAsync方法來做的,你可能還記得,AppUserManager是第13章的用戶管理器類。

...AppUser user = await UserManager.FindAsync(details.Name, details.Password);...

I will be using the AppUserManager class repeatedly in the Account controller, so I defined a property called UserManager that returns the instance of the class using the GetOwinContext extension method for the HttpContext class, just as I did for the Admin controller in Chapter 13.
我會在Account控制器中反復使用AppUserManager類,因此定義了一個名稱為的UserManager屬性,它使用HttpContext類的GetOwinContext擴展方法來返回AppUserManager類的實例。

The FindAsync method takes the account name and password supplied by the user and returns an instance of the user class (AppUser in the example application) if the user account exists and if the password is correct. If there is no such account or the password doesn’t match the one stored in the database, then the FindAsync method returns null, in which case I add an error to the model state that tells the user that something went wrong.
FindAsync方法以用戶提供的賬號名和口令為參數,并在該用戶賬號存在口令正確時,返回一個用戶類(此例中的AppUser)的實例。如果無此賬號,或者與數據庫存儲的不匹配,那么FindAsync方法返回空(null),出現這種情況時,我給模型狀態添加了一條錯誤消息,告訴用戶可能出錯了。

If the FindAsync method does return an AppUser object, then I need to create the cookie that the browser will send in subsequent requests to show they are authenticated. Here are the relevant statements:
如果FindAsync方法確實返回了AppUser對象,那么則需要創建Cookie,瀏覽器會在后繼的請求中發送這個Cookie,表明他們是已認證的。以下是有關語句:

...ClaimsIdentity ident = await UserManager.CreateIdentityAsync(user,        DefaultAuthenticationTypes.ApplicationCookie);AuthManager.SignOut();AuthManager.SignIn(new AuthenticationProperties {IsPersistent = false}, ident);return Redirect(returnUrl);...

The first step is to create a ClaimsIdentity object that identifies the user. The ClaimsIdentity class is the ASP.NET Identity implementation of the IIdentity interface that I described in Table 14-4 and that you can see used in the “Using Roles for Authorization” section later in this chapter.
第一步是創建一個標識該用戶的ClaimsIdentity對象。ClaimsIdentity類是表14-4所描述的IIdentity接口的ASP.NET Identity實現,可以在本章稍后的“使用角色授權”小節中看到它的使用。

Tip Don’t worry about why the class is called ClaimsIdentity at the moment. I explain what claims are and how they can be used in Chapter 15.
提示:此刻不必關心這個類為什么要調用ClaimsIdentity,第15章會解釋什么是聲明(Claims),并介紹如何使用它們。

Instances of ClaimsIdentity are created by calling the user manager CreateIdentityAsync method, passing in a user object and a value from the DefaultAuthenticationTypes enumeration. The ApplicationCookie value is used when working with individual user accounts.
ClaimsIdentity的實例是調用用戶管理器的CreateIdentityAsync方法而創建的,在其中傳遞了一個用戶對象和DefaultAuthenticationTypes枚舉中的一個值。在使用個別用戶賬號進行工作時,會用到ApplicationCookie值。

The next step is to invalidate any existing authentication cookies and create the new one. I defined the AuthManager property in the controller because I’ll need access to the object it provides repeatedly as I build the functionality in this chapter. The property returns an implementation of the IAuthenticationManager interface that is responsible for performing common authentication options. I have described the most useful methods provided by the IAuthenticationManager interface in Table 14-5.
下一個步驟是讓已認證的Cookie失效,并創建一個新的Cookie。我在該控制器中定義了AuthManager屬性,因為在建立本章功能過程中,需要反復訪問它所提供的對象。該屬性返回的是IAuthenticationManager接口的實現,它負責執行常規的認證選項。表14-5中描述了IAuthenticationManager接口所提供的最有用的方法。

Table 14-5. The Most Useful Methods Defined by the IAuthenticationManager Interface
表14-5. IAuthenticationManager接口定義的最有用的方法
Name
名稱
Description
描述
SignIn(options, identity)Signs the user in, which generally means creating the cookie that identifies authenticated requests
簽入用戶,這通常意味著要創建用來標識已認證請求的Cookie
SignOut()Signs the user out, which generally means invalidating the cookie that identifies authenticated requests
簽出用戶,這通常意味著使標識已認證用戶的Cookie失效

The arguments to the SignIn method are an AuthenticationProperties object that configures the authentication process and the ClaimsIdentity object. I set the IsPersistent property defined by the AuthenticationProperties object to true to make the authentication cookie persistent at the browser, meaning that the user doesn’t have to authenticate again when starting a new session. (There are other properties defined by the AuthenticationProperties class, but the IsPersistent property is the only one that is widely used at the moment.)
SignIn方法的參數是一個AuthenticationProperties對象,用以配置認證過程以及ClaimsIdentity對象。我將AuthenticationProperties對象定義的IsPersistent屬性設置為true,以使認證Cookie在瀏覽器中是持久化的,意即用戶在開始新會話時,不必再次進行認證。(AuthenticationProperties類還定義了一些其他屬性,但IsPersistent屬性是此刻唯一要廣泛使用的一個屬性。)

The final step is to redirect the user to the URL they requested before the authentication process started, which I do by calling the Redirect method.
最后一步是將用戶重定向到他們在認證過程開始之前所請求的URL,這是通過調用Redirect方法實現的。

CONSIDERING TWO-FACTOR AUTHENTICATION
考慮雙因子認證

I have performed single-factor authentication in this chapter, which is where the user is able to authenticate using a single piece of information known to them in advance: the password.
在本章中,我實行的是單因子認證,在這種場合中,用戶只需使用一個他們預知的單一信息片段:口令,便能夠進行認證。

ASP.NET Identity also supports two-factor authentication, where the user needs something extra, usually something that is given to the user at the moment they want to authenticate. The most common examples are a value from a SecureID token or an authentication code that is sent as an e-mail or text message (strictly speaking, the two factors can be anything, including fingerprints, iris scans, and voice recognition, although these are options that are rarely required for most web applications).
ASP.NET Identity還支持雙因子認證,在這種情況下,用戶需要一些附加信息,通常是在他們需要認證時才發給他們的某種信息。最常用的例子是SecureID令牌的值,或者是通過E-mail發送的認證碼或文本消息(嚴格地講,第二因子可以是任何東西,包括指紋、眼瞳掃描、聲音識別等,盡管這些是在大多數Web應用程序中很少需要用到的選項。)

Security is increased because an attacker needs to know the user’s password and have access to whatever provides the second factor, such an e-mail account or cell phone.
這樣增加了安全性,因為攻擊者需要知道用戶的口令,并且能夠對提供第二因子的客戶端進行訪問,如E-mail賬號或移動電話等。

I don’t show two-factor authentication in the book for two reasons. The first is that it requires a lot of preparatory work, such as setting up the infrastructure that distributes the second-factor e-mails and texts and implementing the validation logic, all of which is beyond the scope of this book.
本章不演示雙因子認證有兩個原因。第一是它需要許多準備工作,例如要建立分發第二因子的郵件和文本的基礎架構,并實現驗證邏輯,這些都超出了本書的范圍。

The second reason is that two-factor authentication forces the user to remember to jump through an additional hoop to authenticate, such as remembering their phone or keeping a security token nearby, something that isn’t always appropriate for web applications. I carried a SecureID token of one sort or another for more than a decade in various jobs, and I lost count of the number of times that I couldn’t log in to an employer’s system because I left the token at home.
第二個原因是雙因子認證強制用戶要記住一個額外的認證令牌,例如,要記住他們的電話,或者將安全令牌帶在身邊,這對Web應用程序而言,并非總是合適的。我十幾年在各種工作中都帶著這種或那種SecureID令牌,而且我有數不清的次數無法登錄雇員系統,因為我將令牌丟在了家里。

If you are interested in two-factor security, then I recommend relying on a third-party provider such as Google for authentication, which allows the user to choose whether they want the additional security (and inconvenience) that two-factor authentication provides. I demonstrate third-party authentication in Chapter 15.
如果對雙因子安全性有興趣,那么我建議你依靠第三方提供器,例如Google認證,它允許用戶選擇是否希望使用雙因子提供的附加安全性(而且是不方便的)。第15章將演示第三方認證。

14.2.4 Testing Authentication
14.2.4 測試認證

To test user authentication, start the application and request the /Home/Index URL. When redirected to the /Account/Login URL, enter the details of one of the users I listed at the start of the chapter (for instance, the name joe and the password MySecret). Click the Log In button, and your browser will be redirected back to the /Home/Index URL, but this time it will submit the authentication cookie that grants it access to the action method, as shown in Figure 14-3.
為了測試用戶認證,啟動應用程序,并請求/Home/Index URL。當被重定向到/Account/Login URL時,輸入本章開始時列出的一個用戶的細節(例如,姓名為joe,口令為MySecret)。點擊“Log In(登錄)”按鈕,你的瀏覽器將被重定向,回到/Home/Index URL,但這次它將遞交認證Cookie,被準予訪問該動作方法,如圖14-3所示。

圖14-3

Figure 14-3. Authenticating a user
圖14-3. 認證用戶

Tip You can use the browser F12 tools to see the cookies that are used to identify authenticated requests.
提示:可以用瀏覽器的F12工具,看到用來標識已認證請求的Cookie。

14.3 Authorizing Users with Roles
14.3 以角色授權用戶

In the previous section, I applied the Authorize attribute in its most basic form, which allows any authenticated user to execute the action method. In this section, I will show you how to refine authorization to give finer-grained control over which users can perform which actions. Table 14-6 puts authorization in context.
上一小節以最基本的形式運用了Authorize注解屬性,這允許任何已認證用戶執行動作方法。在本小節中,將展示如何精煉授權,以便在用戶能夠執行的動作上有更細粒度的控制。表14-6描述了授權的情形。

Table 14-6. Putting Authorization in Context
表16-4. 授權情形
Question
問題
Answer
答案
What is it?
什么是授權?
Authorization is the process of granting access to controllers and action methods to certain users, generally based on role membership.
授權是將控制器和動作的準許訪問限制到特定用戶,通常是基于角色的成員
Why should I care?
為何要關心它?
Without roles, you can differentiate only between users who are authenticated and those who are not. Most applications will have different types of users, such as customers and administrators.
沒有角色,你只能在已認證用戶和未認證用戶之間加以區分。大多數應用程序均有不同類型的用戶,例如客戶和管理員等
How is it used by the MVC framework?
如何在MVC框架中使用它?
Roles are used to enforce authorization through the Authorize attribute, which is applied to controllers and action methods.
角色通過Authorize注解屬性可用于強制授權,Authorize可用于控制器和動作方法

Tip In Chapter 15, I show you a different approach to authorization using claims, which are an advanced ASP.NET Identity feature.
提示:第15章將使用Claims(聲明)來演示不同的授權辦法,Claims是一種高級的ASP.NET Identity特性。

14.3.1 Adding Support for Roles
14.3.1 添加角色支持

ASP.NET Identity provides a strongly typed base class for accessing and managing roles called RoleManager<T> , where T is the implementation of the IRole interface supported by the storage mechanism used to represent roles. The Entity Framework uses a class called IdentityRole to implement the IRole interface, which defines the properties shown in Table 14-7.
ASP.NET Identity為訪問和管理角色提供了一個強類型的基類,叫做RoleManager<T> ,其中TIRole接口的實現,該實現得到了用來表示角色的存儲機制的支持。Entity Framework實現了IRole接口,使用的是一個名稱為IdentityRole的類,它定義了如表14-7所示的屬性。

Table 14-7. The Properties Defined by the IdentityRole Class
表14-7. IdentityRole類所定義的屬性
Name
名稱
Description
描述
IdDefines the unique identifier for the role
定義角色的唯一標識符
Name Defines the name of the role
定義角色名稱
UsersReturns a collection of IdentityUserRole objects that represents the members of the role
返回一個代表角色成員的IdentityUserRole對象集合

I don’t want to leak references to the IdentityRole class throughout my application because it ties me to the Entity Framework for storing role data, so I start by creating an application-specific role class that is derived from IdentityRole. I added a class file called AppRole.cs to the Models folder and used it to define the class shown in Listing 14-6.
我不希望在整個應用程序中都暴露對IdentityRole類的引用,因為它為了存儲角色數據,將我綁定到了Entity Framework。為此,我首先創建了一個應用程序專用的角色類,它派生于IdentityRole。我在Models文件夾中添加了一個類文件,名稱為AppRole.cs,并用它定義了這個類,如清單14-6所示。

Listing 14-6. The Contents of the AppRole.cs File
清單14-6. AppRole文件的內容

using Microsoft.AspNet.Identity.EntityFramework; 
namespace Users.Models { public class AppRole : IdentityRole {
public AppRole() : base() {}
public AppRole(string name) : base(name) { } }}

The RoleManager<T> class Operates on instances of the IRole implementation class through the methods and properties shown in Table 14-8.
RoleManager<T> 類通過表14-8所示的方法和屬性對IRole實現類的實例進行操作。

Table 14-8. The Members Defined by the RoleManager<T> Class
表14-8. RoleManager<T>類定義的成員
Name
名稱
Description
描述
CreateAsync(role)Creates a new role
創建一個新角色
DeleteAsync(role)Deletes the specified role
刪除指定角色
FindByIdAsync(id) Finds a role by its ID
找到指定ID的角色
FindByNameAsync(name)Finds a role by its name
找到指定名稱的角色
RoleExistsAsync(name) Returns true if a role with the specified name exists
如果存在指定名稱的角色,返回true
UpdateAsync(role) Stores changes to the specified role
將修改存儲到指定角色
RolesReturns an enumeration of the roles that have been defined
返回已被定義的角色枚舉

These methods follow the same basic pattern of theUserManager<T> class that I described in Chapter 13. Following the pattern I used for managing users, I added a class file called AppRoleManager.cs to the Infrastructure folder and used it to define the class shown in Listing 14-7.
這些方法與第13章描述的UserManager<T> 類有同樣的基本模式。按照對管理用戶所采用的模式,我在Infrastructure文件夾中添加了一個類文件,名稱為AppRoleManager.cs,用它定義了如清單14-7所示的類。

Listing 14-7. The Contents of the AppRoleManager.cs File
清單14-7. AppRoleManager.cs文件的內容

using System;using Microsoft.AspNet.Identity;using Microsoft.AspNet.Identity.EntityFramework;using Microsoft.AspNet.Identity.Owin;using Microsoft.Owin; using Users.Models; 
namespace Users.Infrastructure {
public class AppRoleManager : RoleManager<AppRole>, IDisposable {
public AppRoleManager(RoleStore<AppRole> store) : base(store) { }
public static AppRoleManager Create( IdentityFactoryOptions<AppRoleManager> options, IOwinContext context) { return new AppRoleManager(new RoleStore<AppRole>(context.Get<AppIdentityDbContext>())); } }}

This class defines a Create method that will allow the OWIN start class to create instances for each request where Identity data is accessed, which means I don’t have to disseminate details of how role data is stored throughout the application. I can just obtain and operate on instances of the AppRoleManager class. You can see how I have registered the role manager class with the OWIN start class, IdentityConfig, in Listing 14-8. This ensures that instances of the AppRoleManager class are created using the same Entity Framework database context that is used for the AppUserManager class.
這個類定義了一個Create方法,它讓OWIN啟動類能夠為每一個訪問Identity數據的請求創建實例,這意味著在整個應用程序中,我不必散布如何存儲角色數據的細節,卻能獲取AppRoleManager類的實例,并對其進行操作。在清單14-8中可以看到如何用OWIN啟動類(IdentityConfig)來注冊角色管理器類。這樣能夠確保,可以使用與AppUserManager類所用的同一個Entity Framework數據庫上下文,來創建AppRoleManager類的實例。

Listing 14-8. Creating Instances of the AppRoleManager Class in the IdentityConfig.cs File
清單14-8. 在IdentityConfig.cs文件中創建AppRoleManager類的實例

using Microsoft.AspNet.Identity;using Microsoft.Owin;using Microsoft.Owin.Security.Cookies;using Owin;using Users.Infrastructure; 
namespace Users { public class IdentityConfig { public void Configuration(IAppBuilder app) {
app.CreatePerOwinContext<AppIdentityDbContext>(AppIdentityDbContext.Create); app.CreatePerOwinContext<AppUserManager>(AppUserManager.Create); app.CreatePerOwinContext<AppRoleManager>(AppRoleManager.Create); app.UseCookieAuthentication(new CookieAuthenticationOptions { AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, LoginPath = new PathString("/Account/Login"), }); } }}

14.3.2 Creating and Deleting Roles
14.3.2 創建和刪除角色

Having prepared the application for working with roles, I am going to create an administration tool for managing them. I will start the basics and define action methods and views that allow roles to be created and deleted. I added a controller called RoleAdmin to the project, which you can see in Listing 14-9.
現在已經做好了應用程序使用角色的準備,我打算創建一個管理工具來管理角色。首先從基本的開始,定義能夠創建和刪除角色的動作方法和視圖。我在項目中添加了一個控制器,名稱為RoleAdmin,如清單14-9所示。

Listing 14-9. The Contents of the RoleAdminController.cs File
清單14-9. RoleAdminController.cs文件的內容

using System.ComponentModel.DataAnnotations;using System.Linq; using System.Threading.Tasks;using System.Web; using System.Web.Mvc; using Microsoft.AspNet.Identity; using Microsoft.AspNet.Identity.Owin;using Users.Infrastructure; using Users.Models; 
namespace Users.Controllers { public class RoleAdminController : Controller {
public ActionResult Index() { return View(RoleManager.Roles); }
public ActionResult Create() { return View(); }
[HttpPost] public async Task<ActionResult> Create([Required]string name) { if (ModelState.IsValid) { IdentityResult result = await RoleManager.CreateAsync(new AppRole(name)); if (result.Succeeded) { return RedirectToAction("Index"); } else { AddErrorsFromResult(result); } } return View(name); }
[HttpPost] public async Task<ActionResult> Delete(string id) { AppRole role = await RoleManager.FindByIdAsync(id); if (role != null) { IdentityResult result = await RoleManager.DeleteAsync(role); if (result.Succeeded) { return RedirectToAction("Index"); } else { return View("Error", result.Errors); } } else { return View("Error", new string[] { "Role Not Found" }); } }
private void AddErrorsFromResult(IdentityResult result) { foreach (string error in result.Errors) { ModelState.AddModelError("", error); } }
private AppUserManager UserManager { get { return HttpContext.GetOwinContext().GetUserManager<AppUserManager>(); } }
private AppRoleManager RoleManager { get { return HttpContext.GetOwinContext().GetUserManager<AppRoleManager>(); } } }}

I have applied many of the same techniques that I used in the Admin controller in Chapter 13, including a UserManager property that obtains an instance of the AppUserManager class and an AddErrorsFromResult method that processes the errors reported in an IdentityResult object and adds them to the model state.
這里運用了許多第13章中Admin控制器所采用的同樣技術,包括一個UserManager屬性,用于獲取AppUserManager類的實例;和一個AddErrorsFromResult方法,用來處理IdentityResult對象所報告的消息,并將消息添加到模型狀態。

I have also defined a RoleManager property that obtains an instance of the AppRoleManager class, which I used in the action methods to obtain and manipulate the roles in the application. I am not going to describe the action methods in detail because they follow the same pattern I used in Chapter 13, using the AppRoleManager class in place of AppUserManager and calling the methods I described in Table 14-8.
我還定義了RoleManager屬性,用來獲取AppRoleManager類的實例,在動作方法中用該實例獲取并維護應用程序的角色。我不打算詳細描述這些動作方法,因為它們遵循著與第13章同樣的模式,在使用AppUserManager的地方使用了AppRoleManager類,調用的是表14-8中的方法。

14.3.3 Creating the Views
14.3.3 創建視圖

The views for the RoleAdmin controller are standard HTML and Razor markup, but I have included them in this chapter so that you can re-create the example. I want to display the names of the users who are members of each role. The Entity Framework IdentityRole class defines a Users property that returns a collection of IdentityUserRole user objects representing the members of the role. Each IdentityUserRole object has a UserId property that returns the unique ID of a user, and I want to get the username for each ID. I added a class file called IdentityHelpers.cs to the Infrastructure folder and used it to define the class shown in Listing 14-10.
RoleAdmin控制器的視圖是標準的HTML和Razor標記,但我還是將它們包含在本章之中,以便你能夠重建本章的示例。我希望顯示每個角色中成員的用戶名。Entity Framework的IdentityRole類中定義了一個Users屬性,它能夠返回表示角色成員的IdentityUserRole用戶對象集合。每一個IdentityUserRole對象都有一個UserId屬性,它返回一個用戶的唯一ID,不過,我希望得到的是每個ID所對應的用戶名。我在Infrastructure文件夾中添加了一個類文件,名稱為IdentityHelpers.cs,用它定義了如清單14-10所示的類。

Listing 14-10. The Contents of the IdentityHelpers.cs File
清單14-10. IdentityHelpers.cs文件的內容

using System.Web;using System.Web.Mvc;using Microsoft.AspNet.Identity.Owin; 
namespace Users.Infrastructure { public static class IdentityHelpers {
public static MvcHtmlString GetUserName(this HtmlHelper html, string id) { AppUserManager mgr = HttpContext.Current.GetOwinContext().GetUserManager<AppUserManager>(); return new MvcHtmlString(mgr.FindByIdAsync(id).Result.UserName); } }}

Custom HTML helper methods are defined as extensions on the HtmlHelper class. My helper, which is called GetUsername, takes a string argument containing a user ID, obtains an instance of the AppUserManager through the GetOwinContext.GetUserManager method (where GetOwinContext is an extension method on the HttpContext class), and uses the FindByIdAsync method to locate the AppUser instance associated with the ID and to return the value of the UserName property.
這個自定義的HTML輔助器方法,是作為HtmlHelper類的擴展進行定義的。該輔助器的名稱為GetUsername,以一個含有用戶ID的字符串為參數,通過GetOwinContext.GetUserManager方法獲取AppUserManager的一個實例(其中GetOwinContextHttpContext類的擴展方法),并使用FindByIdAsync方法定位與ID相關聯的AppUser實例,然后返回UserName屬性的值。

Listing 14-11 shows the contents of the Index.cshtml file from the Views/RoleAdmin folder, which I created by right-clicking the Index action method in the code editor and selecting Add View from the pop-up menu.
清單14-11顯示了Views/RoleAdmin文件夾中Index.cshtml文件的內容,這是通過在代碼編輯器中右擊Index動作,并從彈出菜單中選擇“Add View(添加視圖)”來創建的。

Listing 14-11. The Contents of the Index.cshtml File in the Views/RoleAdmin Folder
清單14-11. Views/RoleAdmin文件夾中Index.cshtml文件的內容

@using Users.Models@using Users.Infrastructure@model IEnumerable<AppRole>@{ ViewBag.Title = "Roles"; }
<div class="panel panel-primary"> <div class="panel-heading">Roles</div> <table class="table table-striped">
<tr><th>ID</th><th>Name</th><th>Users</th><th></th></tr> @if (Model.Count() == 0) { <tr><td colspan="4" class="text-center">No Roles</td></tr> } else { foreach (AppRole role in Model) { <tr> <td>@role.Id</td> <td>@role.Name</td> <td> @if (role.Users == null || role.Users.Count == 0) { @: No Users in Role } else { <p>@string.Join(", ", role.Users.Select(x => Html.GetUserName(x.UserId)))</p> } </td> <td> @using (Html.BeginForm("Delete", "RoleAdmin", new { id = role.Id })) { @Html.ActionLink("Edit", "Edit", new { id = role.Id }, new { @class = "btn btn-primary btn-xs" }) <button class="btn btn-danger btn-xs" type="submit"> Delete </button> } </td> </tr> } } </table></div>@Html.ActionLink("Create", "Create", null, new { @class = "btn btn-primary" })

This view displays a list of the roles defined by the application, along with the users who are members, and I use the GetUserName helper method to get the name for each user.
該視圖顯示了一個由應用程序定義的角色列表,且帶有成員用戶,我用GetUserName輔助器方法獲取了每個用戶的用戶名。

Listing 14-12 shows the Views/RoleAdmin/Create.cshtml file, which I created to allow new roles to be created.
清單14-12顯示了Views/RoleAdmin/Create.cshtml文件,這是用來創建新角色的視圖。

Listing 14-12. The Contents of the Create.cshtml File in the Views/RoleAdmin Folder
清單14-12. Views/RoleAdmin文件夾中Create.cshtml文件的內容

@model string@{ ViewBag.Title = "Create Role";}<h2>Create Role</h2>@Html.ValidationSummary(false)@using (Html.BeginForm()) {    <div class="form-group">        <label>Name</label>        <input name="name" value="@Model" class="form-control" />    </div>    <button type="submit" class="btn btn-primary">Create</button>    @Html.ActionLink("Cancel", "Index", null, new { @class = "btn btn-default" })}

The only information required to create a new view is a name, which I gather using a standard input element and submit the value to the Create action method.
創建該視圖需要的唯一信息是角色名,我用標準的input元素進行采集,并將該值遞交給Create動作方法。

14.3.4 Testing Creating and Deleting Roles
14.3.4 測試角色的創建和刪除

To test the new controller, start the application and navigate to the /RoleAdmin/Index URL. To create a new role, click the Create button, enter a name in the input element, and click the second Create button. The new view will be saved to the database and displayed when the browser is redirected to the Index action, as shown in Figure 14-4. You can remove the role from the application by clicking the Delete button.
為了測試新的控制器,啟動應用程序并導航到/RoleAdmin/Index URL。為了創建一個新的角色,點擊“Create”按鈕,在input元素中輸入一個角色名,然后點擊第二個“Create”按鈕。新角色將被保存到數據庫,并在瀏覽器被重定向到Index動作時顯示出來,如圖14-4所示。可以點擊“Delete”按鈕將該角色從應用程序中刪除。

圖14-4

Figure 14-4. Creating a new role
圖14-4. 創建新角色

14.3.5 Managing Role Memberships
14.3.5 管理角色成員

To authorize users, it isn’t enough to just create and delete roles; I also have to be able to manage role memberships, assigning and removing users from the roles that the application defines. This isn’t a complicated process, but it invokes taking the role data from the AppRoleManager class and then calling the methods defined by the AppUserMangager class that associate users with roles.
為了授權用戶,僅僅創建和刪除角色還不夠。還必須能夠管理角色成員,從應用程序定義的角色中指定和除去用戶。這不是一個復雜的過程,但它要從AppRoleManager類獲取角色數據,然后調用將用戶與角色關聯在一起的AppUserMangager類所定義的方法。

I started by defining view models that will let me represent the membership of a role and receive a new set of membership instructions from the user. Listing 14-13 shows the additions I made to the UserViewModels.cs file.
我首先定義了視圖模型,這讓我能夠表示一個角色中的成員,并能夠從用戶那里接收一組新成員的指令。清單14-13顯示了在UserViewModels.cs文件中所做的添加。

Listing 14-13. Adding View Models to the UserViewModels.cs File
清單14-13. 添加到UserViewModels.cs文件的視圖模型

using System.ComponentModel.DataAnnotations;using System.Collections.Generic; 
namespace Users.Models {
public class CreateModel { [Required] public string Name { get; set; } [Required] public string Email { get; set; } [Required] public string Password { get; set; } }
public class LoginModel { [Required] public string Name { get; set; } [Required] public string Password { get; set; } }
public class RoleEditModel { public AppRole Role { get; set; } public IEnumerable<AppUser> Members { get; set; } public IEnumerable<AppUser> NonMembers { get; set; } }
public class RoleModificationModel { [Required] public string RoleName { get; set; } public string[] IdsToAdd { get; set; } public string[] IdsToDelete { get; set; } }
}

The RoleEditModel class will let me pass details of a role and details of the users in the system, categorized by membership. I use AppUser objects in the view model so that I can extract the name and ID for each user in the view that will allow memberships to be edited. The RoleModificationModel class is the one that I will receive from the model binding system when the user submits their changes. It contains arrays of user IDs rather than AppUser objects, which is what I need to change role memberships.
RoleEditModel類使我能夠在系統中傳遞角色細節和用戶細節,按成員進行歸類。我在視圖模型中使用了AppUser對象,以使我在編輯成員的視圖中能夠為每個用戶提取用戶名和ID。RoleModificationModel類是在用戶遞交他們的修改時,從模型綁定系統接收到的一個類。它含有用戶ID的數組,而不是AppUser對象,這是對角色成員進行修改所需要的。

Having defined the view models, I can add the action methods to the controller that will allow role memberships to be defined. Listing 14-14 shows the changes I made to the RoleAdmin controller.
定義了視圖模型之后,便可以在控制器中添加動作方法,以便定義角色成員。清單14-14顯示了我對RoleAdmin控制器所做的修改。

Listing 14-14. Adding Action Methods in the RoleAdminController.cs File
清單14-14. 在RoleAdminController.cs文件中添加動作方法

using System.ComponentModel.DataAnnotations;using System.Linq;using System.Threading.Tasks;using System.Web;using System.Web.Mvc;using Microsoft.AspNet.Identity;using Microsoft.AspNet.Identity.Owin;using Users.Infrastructure;using Users.Models;using System.Collections.Generic;
namespace Users.Controllers { public class RoleAdminController : Controller {
// ...other action methods omitted for brevity... // ...出于簡化,這里忽略了其他動作方法 ...
public async Task<ActionResult> Edit(string id) { AppRole role = await RoleManager.FindByIdAsync(id); string[] memberIDs = role.Users.Select(x => x.UserId).ToArray(); IEnumerable<AppUser> members = UserManager.Users.Where(x => memberIDs.Any(y => y == x.Id)); IEnumerable<AppUser> nonMembers = UserManager.Users.Except(members); return View(new RoleEditModel { Role = role, Members = members, NonMembers = nonMembers }); }
[HttpPost] public async Task<ActionResult> Edit(RoleModificationModel model) { IdentityResult result; if (ModelState.IsValid) { foreach (string userId in model.IdsToAdd ?? new string[] { }) { result = await UserManager.AddToRoleAsync(userId, model.RoleName); if (!result.Succeeded) { return View("Error", result.Errors); } } foreach (string userId in model.IdsToDelete ?? new string[] { }) { result = await UserManager.RemoveFromRoleAsync(userId, model.RoleName); if (!result.Succeeded) { return View("Error", result.Errors); } } return RedirectToAction("Index"); } return View("Error", new string[] { "Role Not Found" }); }
private void AddErrorsFromResult(IdentityResult result) { foreach (string error in result.Errors) { ModelState.AddModelError("", error); } }
private AppUserManager UserManager { get { return HttpContext.GetOwinContext().GetUserManager<AppUserManager>(); } }
private AppRoleManager RoleManager { get { return HttpContext.GetOwinContext().GetUserManager<AppRoleManager>(); } } }}

The majority of the code in the GET version of the Edit action method is responsible for generating the sets of members and nonmembers of the selected role, which is done using LINQ. Once I have grouped the users, I call the View method, passing a new instance of the RoleEditModel class I defined in Listing 14-13.
GETEdit動作方法的主要代碼是負責生成一組所選角色的成員和非成員,這是用LINQ完成的。一旦對用戶進行了分組,便調用View方法,為其傳遞了清單14-13所定義的RoleEditModel類的新實例。

The POST version of the Edit method is responsible for adding and removing users to and from roles. The AppUserManager class inherits a number of role-related methods from its base class, which I have described in Table 14-9.
POST版的Edit方法是負責從角色中添加和刪除用戶。AppUserManager類從它的基類繼承了幾個與角色有關的方法,描述于表14-9。

Table 14-9. The Role-Related Methods Defined by the UserManager<T> Class
表14-9. UserManager<T>類中所定義的與角色有關的方法
Name
名稱
Description
描述
AddToRoleAsync(id, name) Adds the user with the specified ID to the role with the specified name
將指定ID的用戶添加到指定name的角色
GetRolesAsync(id) Returns a list of the names of the roles of which the user with the specified ID is a member
返回指定ID的用戶所在的角色名列表
IsInRoleAsync(id, name) Returns true if the user with the specified ID is a member of the role with the specified name
如果指定ID的用戶是指定name角色的成員,返回true
RemoveFromRoleAsync(id, name) Removes the user with the specified ID as a member from the role with the specified name
在指定name角色的成員中除去指定ID的用戶

An oddity of these methods is that the role-related methods operate on user IDs and role names, even though roles also have unique identifiers. It is for this reason that my RoleModificationModel view model class has a RoleName property.
這些方法的奇怪之處在于,與角色有關的方法都根據“用戶ID”和“角色name(角色名)”進行操作,盡管角色也具有唯一標識符(ID)。這也是在RoleModificationModel視圖模型類中使用RoleName屬性的原因。

Listing 14-15 shows the view for the Edit.cshtml file, which I added to the Views/RoleAdmin folder and used to define the markup that allows the user to edit role memberships.
清單14-15顯示了Edit.cshtml文件的視圖,該視圖放在Views/RoleAdmin文件中,用它定義了讓用戶編輯角色成員的標記。

Listing 14-15. The Contents of the Edit.cshtml File in the Views/RoleAdmin Folder
清單14-15. Views/RoleAdmin文件夾中Edit.cshtml文件的內容

@using Users.Models@model RoleEditModel@{ ViewBag.Title = "Edit Role";}@Html.ValidationSummary()@using (Html.BeginForm()) {    <input type="hidden" name="roleName" value="@Model.Role.Name" />    <div class="panel panel-primary">        <div class="panel-heading">Add To @Model.Role.Name</div>        <table class="table table-striped">            @if (Model.NonMembers.Count() == 0) {                <tr><td colspan="2">All Users Are Members</td></tr>            } else {                <tr><td>User ID</td><td>Add To Role</td></tr>                foreach (AppUser user in Model.NonMembers) {                    <tr>                        <td>@user.UserName</td>                        <td>                            <input type="checkbox" name="IdsToAdd" value="@user.Id">                        </td>                    </tr>                }            }        </table>    </div>    <div class="panel panel-primary">        <div class="panel-heading">Remove from @Model.Role.Name</div>        <table class="table table-striped">            @if (Model.Members.Count() == 0) {                <tr><td colspan="2">No Users Are Members</td></tr>            } else {                <tr><td>User ID</td><td>Remove From Role</td></tr>                foreach (AppUser user in Model.Members) {                    <tr>                        <td>@user.UserName</td>                        <td>                            <input type="checkbox" name="IdsToDelete" value="@user.Id">                        </td>                    </tr>                }            }        </table>    </div>    <button type="submit" class="btn btn-primary">Save</button>    @Html.ActionLink("Cancel", "Index", null, new { @class = "btn btn-default" })}

The view contains two tables: one for users who are not members of the selected role and one for those who are members. Each user’s name is displayed along with a check box that allows the membership to be changed.
該視圖含有兩個表格:一個用于不是所選角色成員的用戶,一個是所選角色成員的用戶。每個被顯示出來的用戶名稱旁邊都有一個復選框,可以修改其成員情況。

14.3.6 Testing Editing Role Membership
14.3.6 測試角色成員的編輯

Adding the AppRoleManager class to the application causes the Entity Framework to delete the contents of the database and rebuild the schema, which means that any users you created in the previous chapter have been removed. So that there are users to assign to roles, start the application and navigate to the /Admin/Index URL and create users with the details in Table 14-10.
在應用程序中添加AppRoleManager類會導致Entity Framework刪除數據庫的內容,并重建數據庫架構,這意味著在上一章創建的用戶都會被刪除。因此,為了有用戶可以賦予角色,需啟動應用程序并導航到/Admin/Index URL,先創建一些如表14-10所示的用戶。

Table 14-10. The Values for Creating Example User
表14-10. 創建示例用戶的值
Name
用戶名
Email
E-mail
Password
口令
Alice [email protected] MySecret
Bob [email protected] MySecret
Joe [email protected] MySecret

Tip deleting the user database is fine for an example application but tends to be a problem in real applications. I show you how to gracefully manage changes to the database schema in Chapter 15.
提示:刪除用戶對示例應用程序而言沒什么問題,但對實際應用程序來說就是一個問題了。第15章將演示如何優雅地修改數據庫架構。

To test managing role memberships, navigate to the /RoleAdmin/Index URL and create a role called Users, following the instructions from the “Testing, Creating, and Deleting Roles” section. Click the Edit button and check the boxes so that Alice and Joe are members of the role but Bob is not, as shown in Figure 14-5.
為了測試角色成員的管理,導航到/RoleAdmin/Index URL,并按照“測試角色的創建和刪除”小節的說明,創建一個名稱為Users的角色。點擊“Edit”按鈕,并選中復選框,使Alice和Joe成為該角色的成員,而Bob別選,如圖14-5所示。

圖14-5

Figure 14-5. Editing role membership
圖14-5. 編輯角色成員

Tip If you get an error that tells you there is already an open a data reader, then you didn’t set the MultipleActiveResultSets setting to true in the connection string in Chapter 13.
提示:如果出現錯誤,告訴你說,已經有一個打開的數據讀取程序,那是因為你并未將第13章連接字符串中的MultipleActiveResultSets設置為true。

Click the Save button, and the controller will update the role memberships and redirect the browser to the Index action. The summary of the Users role will show that Alice and Joe are now members, as illustrated by Figure 14-6.
點擊“Save”按鈕,于是控制器將更新角色成員,并將瀏覽器重定向到Index動作。Users角色的摘要將顯示Alice和Joe現在已經是成員,如圖14-6所示。

圖14-6

Figure 14-6. The effect of adding users to a role
圖14-6. 將用戶添加到角色的效果

14.3.7 Using Roles for Authorization
14.3.7 使用角色進行授權

Now that I have the ability to manage roles, I can use them as the basis for authorization through the Authorize attribute. To make it easier to test role-based authorization, I have added a Logout method to the Account controller, as shown in Listing 14-16, which will make it easier to log out and log in again as a different user to see the effect of role membership.
現在已經能夠管理角色了,通過Authorize注解屬性,還可以將角色作為授權的基礎。為了更易于測試基于角色的授權,我在Account控制器中添加了一個Logout方法,如清單14-16所示,這樣便很容易注銷,也容易作為不同用戶登錄,以看看角色成員的效果。

Listing 14-16. Adding a Logout Method to the AccountController.cs File
清單14-16. 在AccountController.cs文件中添加Logout方法

using System.Threading.Tasks;using System.Web.Mvc;using Users.Models;using Microsoft.Owin.Security;using System.Security.Claims;using Microsoft.AspNet.Identity;using Microsoft.AspNet.Identity.Owin;using Users.Infrastructure;using System.Web; 
namespace Users.Controllers {
[Authorize] public class AccountController : Controller {
[AllowAnonymous] public ActionResult Login(string returnUrl) { ViewBag.returnUrl = returnUrl; return View(); }
[HttpPost] [AllowAnonymous] [ValidateAntiForgeryToken] public async Task<ActionResult> Login(LoginModel details, string returnUrl) { // ...statements omitted for brevity... // ...出于簡化,忽略了一些語句... }
[Authorize] public ActionResult Logout() { AuthManager.SignOut(); return RedirectToAction("Index", "Home"); }
private IAuthenticationManager AuthManager { get { return HttpContext.GetOwinContext().Authentication; } }
private AppUserManager UserManager { get { return HttpContext.GetOwinContext().GetUserManager<AppUserManager>(); } } }}

I have updated the Home controller to add a new action method and pass some information about the authenticated user to the view, as shown in Listing 14-17.
我也更新了Home控制器,添加了一個新的動作方法,并將已認證用戶的一些信息傳遞給視圖,如清單14-17所示。

Listing 14-17. Adding an Action Method and Account Information to the HomeController.cs File
清單14-17. 在HomeController.cs文件中添加動作方法和賬號信息

using System.Web.Mvc;using System.Collections.Generic;using System.Web;using System.Security.Principal;
namespace Users.Controllers {
public class HomeController : Controller {
[Authorize] public ActionResult Index() { return View(GetData("Index")); }
[Authorize(Roles="Users")] public ActionResult OtherAction() { return View("Index", GetData("OtherAction")); }
private Dictionary<string, object> GetData(string actionName) { Dictionary<string, object> dict = new Dictionary<string, object>(); dict.Add("Action", actionName); dict.Add("User", HttpContext.User.Identity.Name); dict.Add("Authenticated", HttpContext.User.Identity.IsAuthenticated); dict.Add("Auth Type", HttpContext.User.Identity.AuthenticationType); dict.Add("In Users Role", HttpContext.User.IsInRole("Users")); return dict;
} }}

I have left the Authorize attribute unchanged for the Index action method, but I have set the Roles property when applying the attribute to the OtherAction method, specifying that only members of the Users role should be able to access it. I also defined a GetData method, which adds some basic information about the user identity, using the properties available through the HttpContext object. The final change I made was to the Index.cshtml file in the Views/Home folder, which is used by both actions in the Home controller, to add a link that targets the Logout method in the Account controller, as shown in Listing 14-18.
我沒有改變Index動作方法上的Authorize注解屬性,但將該屬性運用于OtherAction方法時,已經設置了Roles屬性,指明只有Users角色的成員才能夠訪問它。我還定義了一個GetData方法,它添加了一些有關用戶標識的基本信息,這是通過HttpContext對象可用的屬性獲得的。最后所做的修改是Views/Home文件夾中的Index.cshtml文件,它是由Home控制器中的兩個動作使用的,我在其中添加了一些以Account控制器中的Logout方法為目標的鏈接,如清單14-18所示。

Listing 14-18. Adding a Sign-Out Link to the Index.cshtml File in the Views/Home Folder
清單14-18. 在Views/Home文件夾中的Index.cshtml文件中添加Sign-Out(簽出)鏈接

@{ ViewBag.Title = "Index"; }
<div class="panel panel-primary"> <div class="panel-heading">User Details</div> <table class="table table-striped"> @foreach (string key in Model.Keys) { <tr> <th>@key</th> <td>@Model[key]</td> </tr> } </table></div>
@Html.ActionLink("Sign Out", "Logout", "Account", null, new {@class = "btn btn-primary"})

Tip the Authorize attribute can also be used to authorize access based on a list of individual usernames. This is an appealing feature for small projects, but it means you have to change the code in your controllers each time the set of users you are authorizing changes, and that usually means having to go through the test-and-deploy cycle again. Using roles for authorization isolates the application from changes in individual user accounts and allows you to control access to the application through the memberships stored by ASP.NET Identity.
提示:Authorize注解屬性也能夠用來根據個別用戶名進行授權訪問。這是一個對小型項目很吸引人的特性,但這意味著,你每次授權的用戶集合發生變化時,必須修改控制器中的代碼,這也意味著,要重走一遍從測試到部署的開發周期。使用角色授權將應用程序與修改個別用戶賬號隔離開來,使你能夠通過ASP.NET Identity存儲的成員來控制對應用程序的訪問。

To test the authentication, start the application and navigate to the /Home/Index URL. Your browser will be redirected so that you can enter user credentials. It doesn’t matter which of the user details from Table 14-10 you choose to authenticate with because the Authorize attribute applied to the Index action allows access to any authenticated user.
為了測試認證,啟動應用程序,并導航到/Home/Index URL。瀏覽器將被重定向,讓你輸入用戶憑據。選用表14-10中的哪一個用戶細節進行認證沒有多大關系,因為運用于Index動作的Authorize注解屬性允許任何已認證用戶進行訪問

However, if you now request the /Home/OtherAction URL, the user details you chose from Table 14-10 will make a difference because only Alice and Joe are members of the Users role, which is required to access the OtherAction method.
然而,如果你現在請求/Home/OtherAction URL,從表14-10所選的用戶細節就有區別了,因為只有AliceJoeUsers角色的成員,這是訪問OtherAction方法所必須的。

If you log in as Bob, then your browser will be redirected so that you can be prompted for credentials once again.
如果以Bob登錄,那么瀏覽器將被重定向,可能會提示再次輸入憑據。

Redirecting an already authenticated user for more credentials is rarely a useful thing to do, so I have modified the Login action method in the Account controller to check to see whether the user is authenticated and, if so, redirect them to the shared Error view. Listing 14-19 shows the changes.
重定向已認證用戶要求更多憑據幾乎是一件毫無作用的事,因此,我修改了Account控制器中的Login動作方法,檢查用戶是否已認證,如果是,則將他們重定向到共享的Error視圖,清單14-19顯示了所做的修改。

Listing 14-19. Detecting Already Authenticated Users in the AccountController.cs File
清單14-19. 在AccountController.cs文件中檢測已認證用戶

using System.Threading.Tasks;using System.Web.Mvc;using Users.Models;using Microsoft.Owin.Security;using System.Security.Claims;using Microsoft.AspNet.Identity;using Microsoft.AspNet.Identity.Owin;using Users.Infrastructure;using System.Web; 
namespace Users.Controllers {
[Authorize] public class AccountController : Controller {
[AllowAnonymous] public ActionResult Login(string returnUrl) { if (HttpContext.User.Identity.IsAuthenticated) { return View("Error", new string[] { "Access Denied" }); } ViewBag.returnUrl = returnUrl; return View(); }
[HttpPost] [AllowAnonymous] [ValidateAntiForgeryToken] public async Task<ActionResult> Login(LoginModel details, string returnUrl) { // ...code omitted for brevity... // ...出于簡化,忽略了這里的代碼... }
[Authorize] public ActionResult Logout() { AuthManager.SignOut(); return RedirectToAction("Index", "Home"); }
private IAuthenticationManager AuthManager { get { return HttpContext.GetOwinContext().Authentication; } }
private AppUserManager UserManager { get { return HttpContext.GetOwinContext().GetUserManager<AppUserManager>(); } } }}

Figure 14-7 shows the responses generated for the user Bob when requesting the /Home/Index and /Home/OtherAction URLs.
圖14-7顯示了用戶Bob在請求/Home/Index/Home/OtherAction URL時生成的響應。

圖14-7

Figure 14-7. Using roles to control access to action methods
圖14-7. 使用角色控制對動作方法的訪問

Tip Roles are loaded when the user logs in, which means if you change the roles for the user you are currently authenticated as, the changes won’t take effect until you log out and authenticate.
提示:角色在用戶登錄時就會加載,這意味著,如果修改了當前已認證用戶的角色,這些修改是不會生效的,直到他們退出并重新認證。

14.4 Seeding the Database
14.4 種植數據庫

One lingering problem in my example project is that access to my Admin and RoleAdmin controllers is not restricted.
上述示例項目中一直未消除的一個問題是,對AdminRoleAdmin控制器的訪問是不受限制的。

This is a classic chicken-and-egg problem because in order to restrict access, I need to create users and roles, but the Admin and RoleAdmin controllers are the user management tools, and if I protect them with the Authorize attribute, there won’t be any credentials that will grant me access to them, especially when I first deploy the application.
這是一個經典的雞與蛋的問題,因為,若要限制訪問,則需要預先創建一些用戶和角色,但AdminRoleAdmin控制器又是用戶管理工具,如果用Authorize注解屬性來保護它們,那么就不存在能夠對它們訪問的憑據,特別是在第一次部署應用程序時。

The solution to this problem is to seed the database with some initial data when the Entity Framework Code First feature creates the schema. This allows me to automatically create users and assign them to roles so that there is a base level of content available in the database.
這一問題的解決方案是,在Entity Framework的Code First特性創建數據庫架構時,以一些初始的數據植入數據庫。這樣能夠自動地創建一些用戶,并賦予一定的角色,以使數據庫中有一個基礎級的內容可用。

The database is seeded by adding statements to the PerformInitialSetup method of the IdentityDbInit class, which is the application-specific Entity Framework database setup class. Listing 14-20 shows the changes I made to create an administration user.
種植數據庫的辦法是在IdentityDbInit類的PerformInitialSetup方法中添加一些語句,IdentityDbInit是應用程序專用的Entity Framework數據庫設置類。清單14-20是為了創建管理用戶所做的修改

Listing 14-20. Seeding the Database in the AppIdentityDbContext.cs File
清單14-20. 在AppIdentityDbContext.cs文件中種植數據庫

using System.Data.Entity;using Microsoft.AspNet.Identity.EntityFramework;using Users.Models;using Microsoft.AspNet.Identity;
namespace Users.Infrastructure { 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) { AppUserManager userMgr = new AppUserManager(new UserStore<AppUser>(context)); AppRoleManager roleMgr = new AppRoleManager(new RoleStore<AppRole>(context));
string roleName = "Administrators"; string userName = "Admin"; string password = "MySecret"; string email = "[email protected]";
if (!roleMgr.RoleExists(roleName)) { roleMgr.Create(new AppRole(roleName)); }
AppUser user = userMgr.FindByName(userName); if (user == null) { userMgr.Create(new AppUser { UserName = userName, Email = email }, password); user = userMgr.FindByName(userName); }
if (!userMgr.IsInRole(user.Id, roleName)) { userMgr.AddToRole(user.Id, roleName);
} } }}

Tip For this example, I used the synchronous extension methods to locate and manage the role and user. As I explained in Chapter 13, I prefer the asynchronous methods by default, but the synchronous methods can be useful when you need to perform a sequence of related operations.
提示:在上述示例中,我使用了同步的擴展方法來定位和管理角色和用戶。正如第13章所解釋的那樣,一般情況下我更喜歡異步方法,但是,當需要執行一系列相關操作時,同步方法可能是有用的。

I have to create instances of AppUserManager and AppRoleManager directly because the PerformInitialSetup method is called before the OWIN configuration is complete. I use the RoleManager and AppManager objects to create a role called Administrators and a user called Admin and add the user to the role.
我必須直接創建AppUserManagerAppRoleManager的實例,因為PerformInitialSetup方法是在OWIN配置完成之前就被調用的。我使用RoleManagerAppManager對象創建一個名稱為Administrators的角色,和一個名稱為的Admin的用戶,并將此用戶添加到該角色。

Tip Read Chapter 15 before you add database seeding to your project. I describe database migrations, which allow you to take control of schema changes in the database and which put the seeding logic in a different place.
提示:在項目中添加數據庫種植之前,請先閱讀第15章。我在其中描述了數據庫遷移,這讓你能夠對數據庫中的架構變化進行控制,并可以將種植邏輯放在不同的地方。

With this change, I can use the Authorize attribute to protect the Admin and RoleAdmin controllers. Listing 14-21 shows the change I made to the Admin controller.
經過這種修改,我可以使用Authorize注解屬性來保護AdminRoleAdmin控制器。清單14-21顯示了對Admin控制器所做的修改。

Listing 14-21. Restricting Access in the AdminController.cs File
清單14-21. 在AdminController.cs文件中的限制訪問

using System.Web;using System.Web.Mvc;using Microsoft.AspNet.Identity.Owin;using Users.Infrastructure;using Users.Models;using Microsoft.AspNet.Identity;using System.Threading.Tasks; 
namespace Users.Controllers {
[Authorize(Roles = "Administrators")] public class AdminController : Controller { // ...statements omitted for brevity... // ...出于簡化,忽略了這里的語句... }}

Listing 14-22 shows the corresponding change I made to the RoleAdmin controller.
清單14-22是對RoleAdmin控制器所做的相應修改。

Listing 14-22. Restricting Access in the RoleAdminController.cs File
清單14-22. 在RoleAdminController.cs文件中的限制訪問

using System.ComponentModel.DataAnnotations;using System.Linq;using System.Threading.Tasks;using System.Web;using System.Web.Mvc;using Microsoft.AspNet.Identity;using Microsoft.AspNet.Identity.Owin;using Users.Infrastructure;using Users.Models;using System.Collections.Generic; 
namespace Users.Controllers {
[Authorize(Roles = "Administrators")] public class RoleAdminController : Controller { // ...statements omitted for brevity... // ...出于簡化,忽略了這里的語句... }}

The database is seeded only when the schema is created, which means I need to reset the database to complete the process. This isn’t something you would do in a real application, of course, but I wanted to wait until I demonstrated how authentication and authorization worked before creating the administrator account.
只有在創建架構時才會種植數據庫,這意味著需要重置數據庫才能完成這一過程。當然,這不是在實際項目中可能要做的事情,但我希望等一等,在創建管理員賬號之前,完成認證與授權的演示。

To delete the database, open the Visual Studio SQL Server Object Explorer window and locate and right-click the IdentityDb item. Select Delete from the pop-up menu and check both of the options in the Delete Database dialog window. Click the OK button to delete the database.
為了刪除數據庫,請打開Visual Studio中的“SQL Server對象資源管理器”窗口,找到并右擊“IdentityDb”條目。從彈出菜單選擇“Delete(刪除)”,并在“Delete Database(刪除數據庫)”窗口選中那兩個選項。點擊“OK”按鈕,刪除該數據庫。

Now create an empty database to which the schema will be added by right-clicking the Databases item, selecting Add New Database, and entering IdentityDb in the Database Name field. Click OK to create the empty database.
現在,右擊“Databases(數據庫)”條目,選擇“Add New Database(添加新數據庫)”,并在“Database Name(數據庫名稱)”字段中輸入IdentityDb。點擊OK,創建一個空數據庫。

Tip There are step-by-step instructions with screenshots in Chapter 13 for creating the database.
提示:第13章有創建數據庫的逐步說明和屏幕截圖。

Now start the application and request the /Admin/Index or /RoleAdmin/Index URL. There will be a delay while the schema is created and the database is seeded, and then you will be prompted to enter your credentials. Use Admin as the name and MySecret as the password, and you will be granted access to the controllers.
現在,啟動應用程序,請求/Admin/Index/RoleAdmin/Index URL。在創建數據庫架構以及植入數據庫期間會有一點延時,然后將提示你輸入憑據。使用Admin作為用戶名,MySecret作為口令,將會獲得對該控制器的訪問。

Caution Deleting the database removes the user accounts you created using the details in table 14-10, which is why you would not perform this task on a live database containing user details.
警告:刪除數據庫也刪去了你用表14-10所創建的用戶賬號,正是這一原因,一般不會在一個含有用戶細節的活動數據庫中執行此項任務。

14.5 Summary
14.5 小結

In this chapter, I showed you how to use ASP.NET Identity to authenticate and authorize users. I explained how the ASP.NET life-cycle events provide a foundation for authenticating requests, how to collect and validate credentials users, and how to restrict access to action methods based on the roles that a user is a member of. In the next chapter, I demonstrate some of the advanced features that ASP.NET Identity provides.
在本章中,我演示了如何使用ASP.NET Identity進行用戶認證與授權。解釋了ASP.NET生命周期事件如何提供認證基礎,如何收集和檢驗用戶憑據,以及如何根據用戶的成員角色限制對動作方法的訪問。下一章將演示ASP.NET Identity所提供的一些高級特性。


看完此文如果覺得有所收獲,請給個推薦。
你的推薦是我繼續下去的動力,也會讓更多人關注并獲益,這也是你的貢獻。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 大号bbwassbigav头交 | 蜜桃欧美性大片免费视频 | 国产精品观看在线亚洲人成网 | 欧美黄色大片免费观看 | 午夜色视频在线观看 | 精品一区二区三区免费毛片爱 | 韩毛片 | 国产亚洲欧美视频 | 日韩黄色片免费看 | 一本色道久久久888 国产一国产精品一级毛片 国产精品高潮视频 | 中文字幕精品一区久久久久 | 在线免费日韩 | 亚洲一区在线免费视频 | 成年性羞羞视频免费观看 | 欧美一区二区三区不卡免费观看 | 天天艹综合| 202z中文字幕第一页 | 黄色片视频免费观看 | 日韩色视频 | 国产激爽大片在线播放 | 色播视频网站 | 成人aaaa免费全部观看 | 美女在线视频一区二区 | 成人一区二区三区在线 | 在线视频 欧美日韩 | 成人 日韩 | 国产高潮好爽好大受不了了 | 精品国产一区二区三区免费 | 91精品国产777在线观看 | 蝌蚪久久窝 | 欧美在线小视频 | 精品一区二区三区在线播放 | v11av在线播放 | 毛片一级免费看 | 国产精品久久久久久久久久电影 | 国产精品.com| 一级在线观看视频 | 中国av免费在线观看 | 色柚视频网站ww色 | 一区二区三区无码高清视频 | 色播视频在线播放 |