冯 海

一个程序新人菜鸟的日记,希望大家多多关照。QQ:32316131

【ASP.NET Identity系列教程 2】运用ASP.NET Identity

本系列教程详细、完整、深入地介绍了微软的ASP.NET Identity技术,描述了如何运用ASP.NET Identity实现应用程序的用户管理,以及实现应用程序的认证与授权等相关技术,译者希望本系列教程能成为掌握ASP.NET Identity技术的一份完整而有价值的资料。读者若是能够按照文章的描述,一边阅读、一边实践、一边理解,定能有意想不到的巨大收获!希望本系列博文能够得到广大园友的高度推荐

 

14.2.1 理解认证/授权过程

系统集成到了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);
        }
    }
}

  这种方式使用Authorize注解属性是授权的最一般形式,它限制了对Index动作方法的访问,由用户发送给该动作方法的请求必须是应用程序已认证的用户。

如果启动应用程序,并请求以Home控制器中Index动作为目标的URL(/Home/Index、/Home或/),将会看到如图14-1所示的错误。

图14-1
 
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
描述
Identity Returns 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 

 

IPrincipal.Identity属性返回的IIdentity接口实现通过一些属性提供了有关当前用户的一些基本却有用的信息,表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含有一个处理AuthenticateRequest生命周期事件(第3章曾做过描述)的模块,并使用浏览器发送过来的Cookie确认用户是否已被认证。我很快会演示如何创建这些Cookie。如果用户已被认证,此ASP.NET框架模块便会将IIdentity.IsAuthenticated属性的值设置为true,否则设置为false。(此刻尚未实现让用户进行认证的特性,这意味着在本示例应用程序中,IsAuthenticated属性的值总是false。)
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"),
            });
        }
    }
} 

 浏览器请求/Account/Login时,但因为示例项目中没有相应的控制器或动作,于服务器返回了“404 – 未找到”响应,从而导致了如图14-1所示的错误消息。

14.2.2 Preparing to Implement Authentication
14.2.2 实现认证的准备

虽然请求终止于一条错误消息,但上一小节的请求已勾画出ASP.NET Identity系统是如何切入标准的ASP.NET请求生命周期的。下一个步骤是实现一个控制器,用它来接收对/Account/Login URL的请求,并认证用户。我首先在UserViewModels.cs文件中添加了一个模型类,如清单14-2所示。

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

  

 我在项目中添加了一个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);
        }
    }
}

  

尽管它此刻尚未认证用户,但Account控制器已包含了一些有用的基础结构,我想通过ASP.NET Identity代码对这些结构分别加以解释,很快就会在Login动作方法中添加这些代码。

首先要注意Login动作方法有两个版本,它们都有一个名称为returnUrl的参数。当用户请求一个受限的URL时,他们被重定向到/Account/Login URL上,并带有查询字符串,该字符串指定了一旦用户得到认证后将用户返回的URL,如下所示:

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

  ReturnUrl查询字符串参数的值可让我能够对用户进行重定向,使应用程序公开和保密部分之间的导航成为一个平滑无缝的过程。

一个要注意的是运用于Account控制器的注解属性。管理用户账号的控制器含有只能由已认证用户才能使用的功能,例如口令重置。为此,我在控制器类上运用了Authorize注解属性,然后又在个别动作方法上运用了AllowAnonymous注解属性。这会将这些动作方法默认限制到已认证用户,但又能允许未认证用户登录到应用程序。

最后要注意的是,我运用了ValidateAntiForgeryToken注解属性,该属性与视图中的Html.AntiForgeryToken辅助器方法联合工作,防止Cross-Site Request Forgery(CSRF,跨网站请求伪造)的攻击。CSRF会利用应用程序对用户的信任,因此使用这个辅助器和注解属性对于认证请求是特别重要的。

14.2.4 Testing Authentication
14.2.4 测试认证

为了测试用户认证,启动应用程序,并请求/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 以角色授权用户


上一小节以最基本的形式运用了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可用于控制器和动作方法


提示:第15章将使用Claims(声明)来演示不同的授权办法,Claims是一种高级的ASP.NET Identity特性。

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

ASP.NET Identity为访问和管理角色提供了一个强类型的基类,叫做RoleManager<T> ,其中T是IRole接口的实现,该实现得到了用来表示角色的存储机制的支持。Entity Framework实现了IRole接口,使用的是一个名称为IdentityRole的类,它定义了如表14-7所示的属性。

Table 14-7. The Properties Defined by the IdentityRole Class
表14-7. IdentityRole类所定义的属性
Name
名称
Description
描述
Id Defines the unique identifier for the role
定义角色的唯一标识符
Name Defines the name of the role
定义角色名称
Users Returns a collection of IdentityUserRole objects that represents the members of the role
返回一个代表角色成员的IdentityUserRole对象集合

 
我不希望在整个应用程序中都暴露对IdentityRole类的引用,因为它为了存储角色数据,将我绑定到了Entity Framework。为此,我首先创建了一个应用程序专用的角色类,它派生于IdentityRole。我在Models文件夹中添加了一个类文件,名称为AppRole.cs,并用它定义了这个类,如清单14-6所示。

using Microsoft.AspNet.Identity.EntityFramework; 

namespace Users.Models {
    public class AppRole : IdentityRole {

        public AppRole() : base() {}

        public AppRole(string name) : base(name) { }
    }
}

  

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
将修改存储到指定角色
Roles Returns an enumeration of the roles that have been defined
返回已被定义的角色枚举

 
这些方法与第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>()));
        }
    }
}

  

 

 
 
 
 
 

 

posted @ 2017-05-09 19:05  秋天来了哟  阅读(451)  评论(0)    收藏  举报
认识就是缘份,愿天下人都快乐!
QQ: 32316131
Email: 32316131@qq.com