当我创建一个新的asp.net mvc 4.0应用程序时,我要做的的第一件事之一是创建并设置自定义授权global filter
,如下所示:
//FilterConfig.cs
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
//filters.Add(new HandleErrorAttribute());
filters.Add(new CustomAuthorizationAttribute());
}
然后像这样创建
CustomAuthorizationAttribute
://CustomAuthorizationAttribute.cs
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
//Handle AJAX requests
filterContext.HttpContext.Response.StatusCode = 403;
filterContext.Result = new JsonResult { JsonRequestBehavior = JsonRequestBehavior.AllowGet };
}
else
{
//Handle regular requests
base.HandleUnauthorizedRequest(filterContext); //let FormsAuthentication make the redirect based on the loginUrl defined in the web.config (if any)
}
}
我有两个 Controller :
HomeController
和SecureController
HomeController用
[AllowAnonymous]
属性装饰。SecureController是而不是,带有
[AllowAnonymous]
属性。Index() ActionResult
的HomeController
显示带有简单按钮的 View 。单击按钮时,我对位于
SecureController
内的GetData()方法进行了ajax调用,如下所示:$("#btnButton").click(function () {
$.ajax({
url: '@Url.Action("GetData", "Secure")',
type: 'get',
data: {param: "test"},
success: function (data, textStatus, xhr) {
console.log("SUCCESS GET");
}
});
});
不用说,当我单击按钮时,会触发
CustomAuthorizationAttribute
,因为它是全局过滤器,而且因为SecureController
没有用[AllowAnonymous]
属性修饰。好的,我已经完成了介绍...
随着
asp.net mvc 5.0
的引入,我们现在介绍了一个新的authentication filter
,该代码恰好在授权过滤器之前被触发了(这很棒,这使我们能够更精细地控制如何区分未经身份验证的用户(http 401)来自经过身份验证且恰好未获得授权的用户(http 403)。为了尝试使用这个新的
authentication filter
,我创建了一个新的asp.net mvc 5.0(VS Express 2013 for Web),并执行以下操作:public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
//filters.Add(new HandleErrorAttribute());
filters.Add(new CustomAuthenticationAttribute()); //Notice I'm using the word Authentication and not Authorization
}
然后是属性:
public class CustomAuthenticationAttribute : ActionFilterAttribute, IAuthenticationFilter
{
public void OnAuthentication(AuthenticationContext filterContext)
{
}
public void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext)
{
var user = filterContext.HttpContext.User;
if (user == null || !user.Identity.IsAuthenticated)
{
filterContext.Result = new HttpUnauthorizedResult();
}
}
}
我创建了一个
HomeController
。 HomeController
用[AllowAnonymous]
属性修饰。在从VS 2013启动应用程序之前,我已经在我的CustomAuthenticationAttribute的两种方法(
OnAuthentication
和OnAuthenticationChallenge
)中设置了两个断点。启动应用程序时,我遇到了第一个断点(
OnAuthentication
)。然后,令我惊讶的是,Index() ActionResult
的HomeController
中的代码被执行,只有在我返回View()之后,我才达到OnAuthenticationChallenge()
方法上的断点。问题:
我有两个问题。
问题1)
我的印象是
[AllowAnonymous]
属性将自动地绕过CustomAuthenticationAttribute
中的任何代码,但是我错了!我是否需要手动检查是否存在[AllowAnonymous]
属性,并跳过任何代码?问题2)
为什么在
Index()
的之后,我的HomeController
的OnAuthentication
方法内的代码为何被执行?只是意识到我返回View()之后,OnAuthenticationChallenge()
内部的代码是否被执行?我担心的是,如果用户未通过身份验证,我不希望
Index()
方法中的代码得到执行。也许我看错了方向。
如果有人可以帮助我阐明这一点,那就太好了!
真挚地
文斯
最佳答案
关于:
问题1)
我的印象是[AllowAnonymous]属性将自动绕过我的CustomAuthenticationAttribute中的任何代码,但是我错了!我是否需要手动检查[AllowAnonymous]属性的存在并跳过任何代码?
据我所知[AllowAnonymous]属性与CustomAuthenticationAttribute无关。他们有不同的目的。 [AllowAnonymous]在Authorization上下文中有效,但在Authentication上下文中无效。
身份验证过滤器已实现,用于设置身份验证上下文。例如,
AuthenticationContext为您提供执行身份验证的信息。您可以使用此信息基于当前上下文做出身份验证决定。例如,您可以基于身份验证上下文决定将ActionResult修改为其他结果类型,或者您可以基于身份验证上下文决定更改当前主体等。
OnAuthenticationChallenge方法在OnAuthentication方法之后运行。您可以使用OnAuthenticationChallenge方法对请求执行其他任务。
关于:
问题2)为什么在OnAuthentication之后执行HomeController的Index()方法中的代码?只是意识到我返回View()之后,是否执行了OnAuthenticationChallenge()内部的代码?
这是预期的行为。由于您具有全局注册的身份验证过滤器,因此第一件事是,在执行任何操作之前,它会首先触发您所注意到的OnAuthentication事件。然后在执行索引后执行OnAuthenticationChallenge。操作成功后,与该操作相关的任何身份验证过滤器(即索引)都将运行OnAuthenticationChallenge,以便它可以对操作结果做出贡献。就像在OnAuthenticationChallenge的代码中一样,您可以将ActionResult修改为HttpUnauthorizedResult,这将与ActionResult协商。