当我创建一个新的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 :HomeControllerSecureController
HomeController用[AllowAnonymous]属性装饰。

SecureController是而不是,带有[AllowAnonymous]属性。
Index() ActionResultHomeController显示带有简单按钮的 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();
        }
    }
}

我创建了一个HomeControllerHomeController[AllowAnonymous]属性修饰。

在从VS 2013启动应用程序之前,我已经在我的CustomAuthenticationAttribute的两种方法(OnAuthenticationOnAuthenticationChallenge)中设置了两个断点。

启动应用程序时,我遇到了第一个断点(OnAuthentication)。然后,令我惊讶的是,Index() ActionResult HomeController中的代码被执行,只有在我返回View()之后,我才达到OnAuthenticationChallenge()方法上的断点。

问题:
我有两个问题。

问题1)
我的印象是[AllowAnonymous]属性将自动地绕过CustomAuthenticationAttribute中的任何代码,但是我错了!我是否需要手动检查是否存在[AllowAnonymous]属性,并跳过任何代码?

问题2)
为什么在Index()
之后,我的HomeControllerOnAuthentication方法内的代码为何被执行?只是意识到我返回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协商。

10-06 00:41