asp.net mvc 4在AuthorizeAttribute中的结束请求

时间:2015-08-04 02:49:17

标签: c# asp.net-mvc asp.net-web-api

在我们的asp.net mvc 4项目中,我们使用AuthorizeAttribute来实现访问控制,我们的代码就像这样

public class MyAuthorizeAttribute : AuthorizeAttribute
{
    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        if (IsValid())
        {
            //do something
        }
        else
        {
            httpContext.Response.Redirect("~/Common/NoAuthorize", true);
        }
    }
    protected bool IsValid()
    {
        //custom authentication logic
        return true;
    }
}

Controller标记的MVC MyAuthorizeAttribute。问题是当用户无效时,它应该立即重定向到NoAuthorize页面。但我发现它仍将运行MVC中的代码{{ 1}}。Controller之后就可以了。

我尝试添加RedirecthttpContext.Response.End()。他们都没有工作。那么如何在不运行HttpContext.Current.Response.End()中的代码的情况下立即进行重定向?

2 个答案:

答案 0 :(得分:2)

AuthorizeCore应该返回一个bool值。您不从该方法执行重定向。您应该从HandleUnauthorizedRequest方法

更改路径
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
    if (IsValid())
    {
        return true;
    }
    else
    {
        return false;
    }
}

protected bool IsValid()
{
    //custom authentication logic
    return true;
}

protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) {

    filterContext.Result = new RedirectToRouteResult(
                               new RouteValueDictionary 
                               {
                                   { "action", "ActionName" },
                                   { "controller", "ControllerName" }
                               });
}

答案 1 :(得分:0)

你可以抛出异常。

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        if (IsValid())
        {
            //do something
        }
        else
        {
            // You can throw any exception even custom.
            throw new AuthenticationException("User must be logged in to access this page.");
        }
    }

这取决于您在应用程序中处理异常的方式。我在Global.asax.cs中实现了以下方法。在此方法中,我检查它是否不是HttpException,如果它是AuthenticationException,则将其重定向到ErrorController的相应操作,在本例中为Forbidden方法。

    protected void Application_Error(object sender, EventArgs e)
    {
        var ex = Server.GetLastError();

        if (ex is HttpException)
        {
            var httpEx = ex as HttpException;
            statusCode = httpEx.GetHttpCode();

            switch (httpEx.GetHttpCode())
            {
                case 400:
                    action = "BadRequest";
                    break;

                case 401:
                    action = "Unauthorized";
                    break;

                case 403:
                    action = "Forbidden";
                    break;

                case 404:
                    action = "PageNotFound";
                    break;

                case 500:
                    action = "CustomError";
                    break;

                default:
                    action = "CustomError";
                    break;
            }
        }
        else if (ex is AuthenticationException)
        {
            action = "Forbidden";
            statusCode = 403;
        }

        httpContext.ClearError();
        httpContext.Response.Clear();
        httpContext.Response.StatusCode = statusCode;
        httpContext.Response.TrySkipIisCustomErrors = true;
        routeData.Values["controller"] = "Error";
        routeData.Values["action"] = action;

        controller.ViewData.Model = new HandleErrorInfo(ex, currentController, currentAction);
        ((IController) controller).Execute(new RequestContext(new HttpContextWrapper(httpContext), routeData));
    }

ErrorController Forbidden()操作会重定向到相应的页面,如下所示:

    [ExcludeFromCodeCoverage]
    [AllowAnonymous]
    public ActionResult Forbidden()
    {
        Response.StatusCode = (int)HttpStatusCode.Forbidden;

        var model = (ViewData.Model as HandleErrorInfo);
        string returnUrl = string.Empty;

        if (model != null)
        {
            returnUrl = Url.Action(model.ActionName, model.ControllerName);
        }

        return RedirectToAction("Login", "Account", new { returnUrl = returnUrl, name = "" });
    }