使用Custom AuthorizeAttribute装饰Controller时出现重定向错误

时间:2012-06-04 08:25:24

标签: .net asp.net-mvc authentication authorization

我正在使用VS 2011开发一个asp.net MVC 4应用程序。我有一个带有自定义AuthorizeAttribute的自定义角色提供程序,用于确定用户的角色,如果他们不是访问被拒绝的页面,将重定向到访问被拒绝的页面特殊的角色。到目前为止,当我使用自定义属性修饰任何控制器操作时,我所做的工作正常,但是当我将属性添加到控制器时,IE和FF中的错误会失败。我的自定义属性:

public class AccessDeniedAuthorizeAttribute : AuthorizeAttribute
{
    public string RedirectActionName { get; set; }
    public string RedirectControllerName { get; set; }
    private IAccountRepository _accountRepository;

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        var user = httpContext.User;
        this._accountRepository = new AccountRepository();
        var accessAllowed = false;    
        var allowedRoles = this.Roles.Split(',');

        if (!user.Identity.IsAuthenticated)
        {
            return false;
        }

        // Get roles for current user
        var roles = this._accountRepository.GetRoles(user.Identity.Name);

        foreach (var allowedRole in allowedRoles)
        {
            if (roles.Contains(allowedRole))
            {
                accessAllowed = true;
            }
        }

        if (!accessAllowed)
        {
            return false;
        }

        return base.AuthorizeCore(httpContext);
    }

    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        base.OnAuthorization(filterContext);

        if (filterContext.HttpContext.User.Identity.IsAuthenticated && filterContext.Result is HttpUnauthorizedResult)
        {   
            var values = new RouteValueDictionary(new
            {
                action = this.RedirectActionName == "" ? "AccessDenied" : this.RedirectActionName,
                controller = this.RedirectControllerName == "" ? "Home" : this.RedirectControllerName
            });

            filterContext.Result = new RedirectToRouteResult(values);
        }
    }
}

我还在RegisterGlobalFilters中添加了一个全局属性(我尝试删除它但仍然遇到同样的问题):

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
    filters.Add(new HandleErrorAttribute());
    filters.Add(new System.Web.Mvc.AuthorizeAttribute());
}

当我使用属性修饰动作时,它可以正常工作:

[AccessDeniedAuthorize(RedirectActionName = "AccessDenied", RedirectControllerName = "Home", Roles = "propdat")]
public ActionResult Index()
{
    this.ViewBag.Message = "Welcome.";

    return this.View();
}

但是当我将它添加到Controller时,它会完全断开:

[AccessDeniedAuthorize(RedirectActionName = "AccessDenied", RedirectControllerName = "Home", Roles = "propdat")]
public class HomeController : Controller
{
    public ActionResult Index()
    {
        this.ViewBag.Message = "Welcome.";

        return this.View();
    }

    public ActionResult AccessDenied()
    {
        this.ViewBag.Message = "You are not authorised to view this page. Please contact your administrator.";

        return this.View();            
    }
}

角色通过一个存储库从我的数据库返回,看起来很好。在IE中,我得到了标准的“Internet Explorer无法显示网页”错误,并且在Firefox中是一个非常奇怪的错误:

  

页面未正确重定向
         Firefox检测到服务器正在以永远无法完成的方式重定向此地址的请求。

     
      
  • 此问题有时可能是由禁用或拒绝接受引起的   饼干。
  •   

在IE中,网址仍保留在主页:

http://localhost:1989

但是FF执行重定向,因为url更改为我在属性中指定的视图:

http://localhost:1989/Home/AccessDenied

2 个答案:

答案 0 :(得分:2)

再次看看你的代码:)

您正在使用HomeController装饰AccessDeniedAuthorizeAttribute,但HomeController包含您无法拒绝的AccessDenied操作。

问题是,只要AccessDeniedAuthorizeAttribute尝试将当前用户重定向到AccessDenied操作accessAllowed,就会出现错误,这会将您加载到循环循环。

解决方案是:

AccessDenied动作放在另一个“HelperController”中,不要用你的属性装饰这个HelperController。

或者只是将此属性添加到HomeController中除AccessDenied操作之外的所有操作。

答案 1 :(得分:1)

我认为你需要做的是:

  1. 删除全局过滤器 - 它将做的是锁定每个MVC控制器(而不是WebAPI)上的每个操作 - 强制执行如果用户未经过身份验证或未经过授权,则框架将返回重定向到'登录网址'设置(在身份验证>表单元素中找到 - 假设您正在使用表单身份验证) - 请注意,全局过滤器不会在您的自定义属性中使用重定向网址。

  2. 将自定义属性放在主控制器上,然后将[AllowAnnoymous]属性添加到AccessDenied操作中,最重要的是,将此代码添加到自定义属性(这是确保它跳过[AllowAnnoymous]操作所必需的]属性):

        bool skipAuthorization = 
        filterContext.ActionDescriptor.IsDefined(typeof(AllowAnonymousAttribute), inherit: true) 
        || 
        filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(AllowAnonymousAttribute), inherit: true);
    
        if (skipAuthorization)
        {
            return;
        }
    
  3. BTW告诉你的是你正在获得无限重定向循环...因为初始请求是未经授权的,框架重定向到登录URL,但该请求被授权检查捕获并且自身被重定向......依此类推,直到浏览器放弃并停止循环。