扩展AuthorizeAttribute以检测登录的非用户(如何处理用户授权)

时间:2013-03-09 17:53:53

标签: asp.net-mvc asp.net-membership

环境:ASP.NET MVC 4,Visual Studio 2012

[Authorize]属性验证用户是否具有有效的登录cookie,但它不验证用户是否确实存在。如果在该用户的计算机仍保留持久凭证cookie时删除用户,则会发生这种情况。在这种情况下,允许登录的非用户运行标有[Authorize]属性的控制器操作。

解决方案看起来非常简单:扩展AuthorizeAttribute,并在AuthorizeCore例程中验证用户是否存在。

在我编写此代码供我自己使用之前,我想知道是否有人知道[Authorize]属性中这个漏洞的现成解决方案。

2 个答案:

答案 0 :(得分:3)

您需要一个特殊的身份验证全局操作过滤器。

您的问题的解决方案如下。您必须引入将在调用控制器操作之前执行的全局操作筛选器。此事件名为OnActionExecuting。在此全局操作过滤器中,您还可以处理用户具有有效身份验证cookie但在持久性(DB)中不再存在的方案(并且您必须删除其cookie)。

以下是获得想法的代码示例:

    public class LoadCustomPrincipalAttribute : ActionFilterAttribute 
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
                CustomIdentity customIdentity;

                if (HttpContext.Current.User.Identity.IsAuthenticated)
                {        
                    UserData userData = UserRepository.GetUserByName(HttpContext.Current.User.Identity.Name);

                    if (userData == null)
                    {
                      //TODO: Add here user missing logic, 
                      //throw an exception, override with the custom identity with "false" - 
                      //this boolean means that it have IsAuthenticated on false, but you
                      //have to override this in CustomIdentity!
                      //Of course - at this point you also remove the user cookie from response!
                    }

                    customIdentity = new CustomIdentity(userData, true);
                }
                else
                {
                    customIdentity = new CustomIdentity(new UserData {Username = "Anonymous"}, false);
                }

                HttpContext.Current.User = new CustomPrincipal(customIdentity);

            base.OnActionExecuting(filterContext);
        }
    }

希望对你有所帮助!

不要忘记将此操作过滤器注册为全局过滤器。你可以这样做:

    private static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new LoadCustomPrincipalAttribute());
    }

只是添加这个。别管AuthorizeAttribute。它应该按照它的意思工作。它只是检查HttpContext.Current.User.Identity.IsAuthenticated == true条件。有些情况下你需要覆盖它,但这不是那个。在AuthorizeAttribute开始之前,您确实需要正确的用户/身份验证处理。

答案 1 :(得分:0)

同意彼得。这是我为AngularJs应用程序所做的。创建一个检查锁定日期的属性。使用正确的方法更改YourAppUserManager。

public class LockoutPolicyAttribute : ActionFilterAttribute
{
    public override async Task OnActionExecutingAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
    {
        if (HttpContext.Current.User.Identity.IsAuthenticated)
        {
            var now = DateTime.UtcNow;

            var currentUserId = Convert.ToInt32(HttpContext.Current.User?.Identity?.GetUserId());

            var user = await HttpContext.Current.GetOwinContext().GetUserManager<YourAppUserManager>().FindByIdAsync(currentUserId);

            if (user?.LockedOutUntil >= now)
            {
                actionContext.Response = actionContext.Request.CreateErrorResponse((HttpStatusCode)423, "Account Lockout");
                return;
            }
        }

        base.OnActionExecuting(actionContext);
    }
}

然后让状态代码423的AngularJs拦截服务重定向到登录页面。

switch (response.status) {
            case 423: //Account lockout sent by the server.
                AuthService.logOut();
                window.location.href = '/login';