本系列主要翻译自《ASP.NET MVC Interview Questions and Answers 》- By Shailendra Chauhan,想看英文原版的可访问http://www.dotnettricks.com/free-ebooks自行下载。该书主要分为两部分,ASP.NET MVC 5、ASP.NET WEB API2。本书最大的特点是以面试问答的形式进行展开。通读此书,会帮助你对ASP.NET MVC有更深层次的理解。 由于个人技术水平和英文水平也是有限的,因此错误在所难免,希望大家多多留言指正。 系列导航 Asp.net mvc 知多少(一)
Asp.net mvc 知多少(八)
Q78. 介绍下ASP.NET MVC中的 Filters(过滤器) 和 Attributes(特性)? Ans. ASP.NET MVC 提供了一种简单的方式在action执行之前或之后注入一段代码或逻辑,它就是ASP.NET MVC attributes,通过在Controller或者Action上使用Attributes来修饰即可。可以自定义过滤器或特性通过实现ASP.NET MVC filter 接口或继承并重载ASP.NET MVC filter attribute类。 通常,过滤器被用来执行以下常见的功能点:
Q79. 介绍下ASP.NET MVC中几种不同的Filters(过滤器) ?
Ans. 主要有以下五种类型Filters:
Authentication Filters(认证过滤器)
该过滤器是从ASP.NET MVC5中引入的。IAuthenticationFilter
接口是用来创建自定义认证过滤器。IAuthenticationFilter
定义如下:
public interface IAuthenticationFilter
{
void OnAuthentication(AuthenticationContext filterContext);
void OnAuthenticationChallenge(AuthenticationChallengeContext
filterContext);
}
通过实现IAuthenticationFilter
接口,即可实现自定义的认证过滤特性。
public class CustomAuthenticationFilterAttribute : FilterAttribute,
IAuthenticationFilter
{
public void OnAuthentication(AuthenticationContext filterContext)
{
filterContext.HttpContext.Response.Write("Authentication
Filter<br/>");
}
//Runs after the OnAuthentication method
public void OnAuthenticationChallenge(AuthenticationChallengeContext
filterContext)
{
//TODO: Additional tasks on the request
}
}
Authorization Filters(授权过滤器) - ASP.NET MVC的授权过滤器实现了IAuthorizationFilter
接口。
public interface IAuthorizationFilter
{
void OnAuthorization(AuthorizationContext filterContext);
}
AuthorizeAttribute
提供了以下可重载的方法:
public class AuthorizeAttribute : FilterAttribute, IAuthorizationFilter
{
protected virtual bool AuthorizeCore(HttpContextBase httpContext);
protected virtual void HandleUnauthorizedRequest(AuthorizationContext
filterContext);
public virtual void OnAuthorization(AuthorizationContext filterContext);
protected virtual HttpValidationStatus
OnCacheAuthorization(HttpContextBase httpContext);
}
所以,我们可以通过实现IAuthorizationFilter
接口或者继承AuthorizeAttribute
类然后重载虚方法来创建自定义的授权过滤器。
Action Filters(操作过滤器)
Action filters 在action执行之前和之后执行。IActionFilter
接口提供了OnActionExecuting
和 OnActionExecuted
方法分别对应action之前和action之后执行。
public interface IActionFilter
{
void OnActionExecuting(ActionExecutingContext filterContext);
void OnActionExecuted(ActionExecutedContext filterContext);
}
Result Filters(结果过滤器)
Result filters在为action生成结果之前和和之后执行。返回的结果可以是 ViewResult、PartialViewResult、RedirectToRouteResult、RedirectResult、ContentResult、JsonResult、FileResult 和 EmptyResult ,它们均继承自 ActionResult 类。Result filters 在Action Filters之后调用。
IResultFilter
接口提供了OnResultExecuting
和 OnResultExecuted
方法分别对应生成结果之前和之后执行。
public interface IResultFilter
{
void OnResultExecuted(ResultExecutedContext filterContext);
void OnResultExecuting(ResultExecutingContext filterContext);
}
Exception Filters(异常过滤器) - Exception filters在action或者过滤器执行期间出现异常时执行。IExceptionFilter
接口提供了OnException
方法来处理异常。
public interface IExceptionFilter
{
void OnException(ExceptionContext filterContext);
}
HandleErrorAttribute
类实现了IExceptionFilter
接口。
当HandleError
接收到异常,它会直接返回ASP.NET MVC Views/Shared 文件夹下的Error
视图。
Q80. ASP.NET MVC的 Exception filters(异常过滤)何时执行? Ans. Exception filters 在ASP.NET MVC pipeline(管道)执行期间有一个未处理的异常抛出时被执行。
Q81. ASP.NET MVC中filters(过滤器)的执行顺序是? Ans. 所有的 ASP.NET MVC filter都是按照一定的顺序执行。 执行顺序为:
Q82. ASP.NET MVC中如何配置过滤器?
Ans. 我们可以配置自定义的过滤器为以下三个级别:
Global level(全局级别)
将过滤器注册到Global.asax.cs
文件的Application_Start
方法中:
protected void Application_Start()
{ FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
}
Controller level(控制器级别) 通过将过滤器标记在controller上即可。
[Authorize(Roles = "Admin")]
public class AdminController : Controller
{
//TODO:
}
Action level (操作级别) 通过将过滤器标记在action上即可。
public class UserController : Controller
{
[Authorize(Users = "User1,User2")]
public ActionResult LinkLogin(string provider)
{
// TODO:
return View();
}
}
Q83. ASP.NET MVC中认证和授权是如何工作的? Ans. 像 ASP.NET一样,MVC 也支持 Windows 和Forms 认证。可以通过在Web.config中配置或自己编码。
Q84. ASP.NET MVC中 Forms Authentication 和 Authorization(表单认证和授权)是如何工作的? Ans. 和 ASP.NET一样, MVC Forms authentication在IIS认证完成之后发生。可以在 ASP.NET MVC应用程序中的Web.config文件的forms节点进行配置。 默认的表单认证配置如下:
<system.web>
<authentication mode="Forms">
<forms loginUrl="Login.aspx"
protection="All"
timeout="30"
name=".ASPXAUTH"
path="/"
requireSSL="false"
slidingExpiration="true"
defaultUrl="default.aspx"
cookieless="UseDeviceProfile"
enableCrossAppRedirects="false" />
</authentication>
</system.web>
当SetAuthCookie()
或RedirectFromLoginPage()
被调用时FormsAuthentication
类自动创建认证Cookie。 Authentication cookie(认证Cookie)中包含一个已经加密和签名的FormsAuthenticationTicket
对象的字符串。
可以指定cookie的名称、 版本、目录路径、生效日期、过期日期、是否永久属性来创建FormsAuthenticationTicket
对象 。
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, "userName",
DateTime.Now,
DateTime.Now.AddMinutes(30), // value of time out property
false, // Value of IsPersistent property
String.Empty, FormsAuthentication.FormsCookiePath);
然后就可以使用FormsAuthentication
类的Encrypt
方法来加密ticket。
string encryptedTicket = FormsAuthentication.Encrypt(ticket);
Q85. ASP.NET MVC中如何实现自定义Forms Authentication and Authorization(表单认证和授权)? Ans. 当标准的认证不能满足你的需求,你就需要去修改认证机制去创建自定义的认证方案。一个用户上下文有一个Principal,这个Principal代表用户的身份(Identity)和角色(Role)。用户通过ta的身份进行认证,通过给用户分配角色来进行授权。
ASP.NET 提供了IPrincipal
和IIdentity
接口来表示用户的身份和角色。这两个接口
绑定到HttpContext对象和当前线程。可以通过实习这两个接口来创建自定义的方案。
public class CustomPrincipal : IPrincipal
{
public IIdentity Identity { get; private set; }
public bool IsInRole(string role)
{
if (roles.Any(r => role.Contains(r)))
{
return true;
}
else
{
return false;
}
}
public CustomPrincipal(string Username)
{
this.Identity = new GenericIdentity(Username);
}
public int UserId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string[] roles { get; set; }
}
现在你就可以把CustomPrincipal
对象放入thread(线程)的 CurrentPrincipal
属性和HttpContext的User
属性来完成自定义的认证和授权流程。
如果IsAuthenticated
返回true则表示用户认证成功。我们可以用以下两种方式来完成对用户的验证。
ASP.NET MVC 提供了Authorization
授权过滤器来对用户授权。该过滤器可适用于action级别、控制器级别和全局级别。该过滤器基于AuthorizeAttribute
特性类,可以通过继承该特性并重载OnAuthorization()
方法来对授权过滤器进行自定义。
public class CustomAuthorizeAttribute: AuthorizeAttribute {
protected virtual CustomPrincipal CurrentUser {
get {
return HttpContext.Current.User as CustomPrincipal;
}
}
public override void OnAuthorization(AuthorizationContext filterContext) {
if (filterContext.HttpContext.Request.IsAuthenticated) {
if (!String.IsNullOrEmpty(Roles)) {
if (!CurrentUser.IsInRole(Roles)) {
filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new {
controller = "Error",
action = "AccessDenied"
}));
}
}
if (!String.IsNullOrEmpty(Users)) {
if (!Users.Contains(CurrentUser.UserId.ToString())) {
filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new {
controller = "Error",
action = "AccessDenied"
}));
// base.OnAuthorization(filterContext); //returns to login url
}
}
}
}
}
现在你就可以像下面这样应用自定义的授权过滤器在控制器级别或者action级别。
[CustomAuthorize(Roles= "Admin")]
public class AdminController : BaseController
{
public ActionResult Index()
{
return View();
}
}