C# MVC 5.0[AllowAnonymous]和新的IAAuthenticationFilter

C# MVC 5.0[AllowAnonymous]和新的IAAuthenticationFilter,c#,asp.net-mvc-5,C#,Asp.net Mvc 5,当我创建一个新的asp.net mvc 4.0应用程序时,我要做的第一件事就是创建并设置一个自定义的“授权”全局过滤器,如下所示: //FilterConfig.cs public static void RegisterGlobalFilters(GlobalFilterCollection filters) { //filters.Add(new HandleErrorAttribute()); filters.Add(new CustomAuthorizationAttribute()

当我创建一个新的asp.net mvc 4.0应用程序时,我要做的第一件事就是创建并设置一个自定义的“授权”全局过滤器,如下所示:

//FilterConfig.cs
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
 //filters.Add(new HandleErrorAttribute());
 filters.Add(new 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)
        }
    }
$("#btnButton").click(function () {
    $.ajax({
        url: '@Url.Action("GetData", "Secure")',
        type: 'get',
        data: {param: "test"},
        success: function (data, textStatus, xhr) {
            console.log("SUCCESS GET");
        }
    });
});
然后我创建
CustomAuthorizationAttribute
,如下所示:

//FilterConfig.cs
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
 //filters.Add(new HandleErrorAttribute());
 filters.Add(new 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)
        }
    }
$("#btnButton").click(function () {
    $.ajax({
        url: '@Url.Action("GetData", "Secure")',
        type: 'get',
        data: {param: "test"},
        success: function (data, textStatus, xhr) {
            console.log("SUCCESS GET");
        }
    });
});
我有两个控制器:
HomeController
SecureController

HomeController用
[AllowAnonymous]
属性装饰

SecureController未使用
[AllowAnonymous]
属性修饰

HomeController
Index()ActionResult
显示一个带有简单按钮的视图

当我单击按钮时,我会对
SecureController
中的GetData()方法进行ajax调用,如下所示:

//FilterConfig.cs
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
 //filters.Add(new HandleErrorAttribute());
 filters.Add(new 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)
        }
    }
$("#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
的引入,我们现在引入了一个新的
身份验证过滤器
,它恰好在授权过滤器之前被触发(这很好,让我们能够更精确地控制如何区分未经身份验证的用户(http 401)来自经过身份验证且恰好未经授权的用户(http 403))

为了尝试这个新的
身份验证过滤器
,我创建了一个新的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
[AllowAnonymous]
属性装饰

在从VS 2013启动应用程序之前,我在CustomAuthenticationAttribute的两个方法中设置了两个断点(
OnAuthentication
OnAuthenticationChallenge

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

问题: 我有两个问题

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

问题2) 为什么我的
HomeController
Index()方法中的代码在
OnAuthentication
之后执行?只有当我返回View()后才意识到,
OnAuthenticationChallenge()
中的代码会被执行吗

我担心的是,如果用户未经过身份验证,我不希望执行
Index()
方法中的代码

也许我看错了

如果有人能帮我解释一下,那就太好了

诚恳 文斯

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

据我所知,[AllowAnonymous]属性与CustomAuthenticationAttribute无关。它们有不同的目的。[AllowAnonymous]将在授权上下文中有效,但在身份验证上下文中无效

已实现身份验证筛选器以设置身份验证上下文。例如, AuthenticationContext为您提供执行身份验证的信息。您可以使用此信息根据当前上下文做出身份验证决策。例如,您可以决定根据身份验证上下文将ActionResult修改为不同的结果类型,也可以决定根据身份验证上下文更改当前主体等

OnAuthenticationChallenge方法在OnAuthentication方法之后运行。您可以使用OnAuthenticationChallenge方法对请求执行其他任务

关于: 问题2)为什么HomeController的Index()方法中的代码在OnAuthentication之后被执行?只有当我返回View()后,才意识到OnAuthenticationChallenge()中的代码是否会被执行


这是预期的行为。因为您有一个全局注册的身份验证过滤器,所以第一件事是,在执行任何操作之前,它将首先触发OnAuthentication事件,正如您所注意到的那样。然后在执行索引后执行OnAuthenticationChallenge。一旦操作成功,与该操作(即索引)相关的任何身份验证筛选器都将运行OnAuthenticationChallenge,以便它能够对操作结果作出贡献。正如您在OnAuthenticationChallenge代码中所做的那样,您可以将ActionResult修改为HttpUnauthorizedResult,这将与ActionResult进行协商。

我需要在这里澄清您的第二个问题:

问题2)为什么代码在我的 HomeController在OnAuthentication之后执行?只为 请注意,在返回View()之后,请在 是否执行OnAuthenticationChallenge()

如果要阻止用户在中执行代码,实际上应该在OnAuthentication中测试凭据