MVC 5.0 [AllowAnonymous] and the new IAuthenticationFilter
本文关键字:and the new IAuthenticationFilter AllowAnonymous MVC | 更新日期: 2023-09-27 18:36:33
当我创建一个新的 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)
}
}
我有两个控制器:HomeController
和 SecureController
主控制器用 [AllowAnonymous]
属性进行装饰。
安全控制器不使用 [AllowAnonymous]
属性进行修饰。
HomeController
的Index() ActionResult
显示带有简单按钮的视图。
当我单击该按钮时,我对位于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启动应用程序之前,我在自定义身份验证属性的两个方法(OnAuthentication
和OnAuthenticationChallenge
)中设置了两个断点。
启动应用程序时,我遇到了第一个断点(OnAuthentication
)。然后,令我惊讶的是,我HomeController
Index() ActionResult
内的代码被执行,只有在我返回 View() 之后,我才在 OnAuthenticationChallenge()
方法上遇到断点。
问题:我有两个问题。
问题1)
我的印象是 [AllowAnonymous]
属性会自动绕过我CustomAuthenticationAttribute
中的任何代码,但我错了!我是否需要手动检查 [AllowAnonymous]
属性是否存在并跳过任何代码?
问题2)为什么我的HomeController
的Index()
方法中的代码在OnAuthentication
后执行?只是意识到在我返回 View() 后OnAuthenticationChallenge()
中的代码会被执行吗?
我担心的是,如果用户未经过身份验证,我不希望执行 Index()
方法中的代码。
也许我看错了。
如果有人能帮我阐明这一点,那就太好了!
真诚地Vince
回答问题 1:
[AllowAnnoymous] 属性就像一个标志(它实际上没有实现逻辑)。它的存在只是在执行 OnAuthorization 期间由 [Authorize] 属性检查。反编译 [授权] 属性会显示逻辑:
bool skipAuthorization = filterContext.ActionDescriptor.IsDefined(typeof(AllowAnonymousAttribute), inherit: true)
|| filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(AllowAnonymousAttribute), inherit: true);
if (skipAuthorization)
{
return;
}
[允许匿名] 永远不会"自动"绕过自定义属性中的代码......
因此,问题 1 后半部分的答案是:是的 - 如果您希望自定义属性对 [AllowAnnonymous] 的存在做出反应,则需要在自定义 [Authorize] 属性中对 [AllowAnnonymous] 属性进行检查(类似于上述检查)。
关于 :问题1)我的印象是[AllowAnonymous]属性会自动绕过我的自定义身份验证属性中的任何代码,但我错了!我是否需要手动检查 [AllowAnonymous] 属性是否存在并跳过任何代码?
据我所知,[AllowAnonymous]属性与CustomAuthenticationAttribute无关。它们有不同的目的。[允许匿名] 在授权上下文中有效,但在身份验证上下文中无效。
已实现身份验证筛选器以设置身份验证上下文。例如AuthenticationContext 为您提供用于执行身份验证的信息。 您可以使用此信息根据当前上下文做出身份验证决策。例如,您可以决定根据身份验证上下文将 ActionResult 修改为不同的结果类型,也可以决定根据身份验证上下文等更改当前主体。
OnAuthenticationChallenge 方法在 OnAuthentication 方法之后运行。 您可以使用 OnAuthenticationChallenge 方法对请求执行其他任务。
关于 :问题2)为什么我的 HomeController 的 Index() 方法中的代码在 OnAuthentication 之后被执行?只是意识到在我返回 View() 之后,OnAuthenticationChallenge() 中的代码会被执行吗?
这是预期的行为。由于您有一个全局注册的身份验证过滤器,因此第一件事是,在执行任何操作之前,它将首先触发 OnAuthentication 事件,正如您会注意到的那样。然后在执行索引之后进行 OnAuthenticationChallenge。一旦操作成功,与该操作相关的任何身份验证过滤器(即索引)都将运行 OnAuthenticationChallenge,以便它可以为操作结果做出贡献。正如您在 OnAuthenticationChallenge 的代码中所做的那样,您可以将 ActionResult 修改为 HttpUnauthorizedResult,这将与 ActionResult 协商。
我需要在这里澄清你的第二个问题:
问题2)为什么我的 Index() 方法中的代码是我的 主控制器在身份验证后执行?只到 意识到在我返回 View() 后,在 OnAuthenticationChallenge() 被执行?
如果要阻止用户在您的操作方法中执行代码,则实际上应该在 OnAuthentication 中测试凭据。OnAuthenticationChallenge 是使用自定义结果处理 401 的机会,例如将用户重定向到自定义控制器/操作并为他们提供进行身份验证的机会。
public class CustomAuthenticationAttribute : ActionFilterAttribute, IAuthenticationFilter
{
public void OnAuthentication(AuthenticationContext filterContext)
{
var user = filterContext.HttpContext.User;
if (user == null || !user.Identity.IsAuthenticated)
{
filterContext.Result = new HttpUnauthorizedResult();
}
}
public void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext)
{
// modify filterContext.Result to go somewhere special...if you do
// nothing here they will just go to the site's default login
}
}
下面是筛选器的更完整运行以及如何使用它:http://jameschambers.com/2013/11/working-with-iauthenticationfilter-in-the-mvc-5-framework/
干杯。