我正在使用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
答案 0 :(得分:2)
再次看看你的代码:)
您正在使用HomeController
装饰AccessDeniedAuthorizeAttribute
,但HomeController
包含您无法拒绝的AccessDenied
操作。
问题是,只要AccessDeniedAuthorizeAttribute
尝试将当前用户重定向到AccessDenied
操作accessAllowed
,就会出现错误,这会将您加载到循环循环。
解决方案是:
将AccessDenied
动作放在另一个“HelperController”中,不要用你的属性装饰这个HelperController。
或者只是将此属性添加到HomeController
中除AccessDenied
操作之外的所有操作。
答案 1 :(得分:1)
我认为你需要做的是:
删除全局过滤器 - 它将做的是锁定每个MVC控制器(而不是WebAPI)上的每个操作 - 强制执行如果用户未经过身份验证或未经过授权,则框架将返回重定向到'登录网址'设置(在身份验证>表单元素中找到 - 假设您正在使用表单身份验证) - 请注意,全局过滤器不会在您的自定义属性中使用重定向网址。
将自定义属性放在主控制器上,然后将[AllowAnnoymous]属性添加到AccessDenied操作中,最重要的是,将此代码添加到自定义属性(这是确保它跳过[AllowAnnoymous]操作所必需的]属性):
bool skipAuthorization =
filterContext.ActionDescriptor.IsDefined(typeof(AllowAnonymousAttribute), inherit: true)
||
filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(AllowAnonymousAttribute), inherit: true);
if (skipAuthorization)
{
return;
}
BTW告诉你的是你正在获得无限重定向循环...因为初始请求是未经授权的,框架重定向到登录URL,但该请求被授权检查捕获并且自身被重定向......依此类推,直到浏览器放弃并停止循环。