应用AuthorizeAttribute到ASP.NET MVC 3的区域

6
我正在编写一个Admin MVC 3网站,每个用户只能访问网站的某些部分。我的网站区域与用户角色相同,因此我想在每个区域上放置AuthorizeAttribute,并使用该区域的名称作为角色中的参数。到目前为止,在手动检查每个区域时,这个方法已经实现了,但我希望只需循环遍历所有区域并应用授权过滤器。(我正在使用此自定义FilterProvider-http://www.dotnetcurry.com/ShowArticle.aspx?ID=578)我的代码如下("Gcm"是我的其中一个区域,也是一个角色) :
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
    filters.Add(new HandleErrorAttribute());
    // for all controllers, run AdminAuthorizeAttribute to make sure they're at least logged in
    filters.Add(ObjectFactory.GetInstance<AdminAuthorizeAttribute>());

    AdminAuthorizeAttribute gcmAuthroizeAttribute = ObjectFactory.GetInstance<AdminAuthorizeAttribute>();
    gcmAuthroizeAttribute.Roles = "Gcm";

    var provider = new FilterProvider();
    provider.Add(
        x =>
        x.RouteData.DataTokens["area"] != null && x.RouteData.DataTokens["area"].ToString() == "Gcm"
            ? gcmAuthroizeAttribute
            : null);
    FilterProviders.Providers.Add(provider);
}

有没有人知道如何获取我的应用程序中的所有区域,以便我可以循环遍历它们,而不是硬编码每个区域?

或者如果有更好的想法来对每个区域进行授权,那将不胜感激。

谢谢您的帮助 Saan

3个回答

2
您可以为每个区域创建一个基础控制器,并在基类上放置授权属性。这样,您就可以为每个区域的基础控制器传递区域参数。

0
这是我创建的一个授权属性覆盖的示例。我需要我的授权函数支持两种类型的成员资格,因此您可能不想深入了解函数的内部工作方式,但是AuthorizeCore是主要逻辑发生的地方。在我的情况下,我正在使用实体数据上下文进行检查。
用法:
[AjaxAuthorize(AjaxRole = "Administrators")]
public JsonResult SaveAdministrativeUser(v.... )

代码:
 public class AjaxAuthorizeAttribute : AuthorizeAttribute
    {
        private class HttpAuthorizeFailedResult : ActionResult
        {
            public override void ExecuteResult(ControllerContext context)
            {                
                // Set the response code to 403.   Membership.Provider.Name == "UnitArchiveMembershipProvider"
                context.HttpContext.Response.StatusCode = context.HttpContext. User.Identity is WindowsIdentity ?  401 : 403; 
            }
        }

        public string AjaxRole { get; set;}

        public AjaxAuthorizeAttribute()
        {
            AjaxRole = "Users";
        }

        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
            if (string.IsNullOrEmpty(MvcApplication.Config.DBSettings.Database))
            {
                return true;
            }

            //When authorize parameter is set to false, not authorization should be performed.
            UnitArchiveData db = DataContextFactory.GetWebRequestScopedDataContext<UnitArchiveData>(MvcApplication.Config.DBSettings.GetConnectionString());            


            if (httpContext.User.Identity.IsAuthenticated)
            {
                login_data user = db.login_datas.Where(n => n.EmailAddress == httpContext.User.Identity.Name).FirstOrDefault();
                if (user != null)
                {
                    return user.cd_login_role.RoleName == "Administrators" || user.cd_login_role.RoleName == AjaxRole;
                }
            }

            return false;

        }

        protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
        {
            if (filterContext.RequestContext.HttpContext.Request.IsAjaxRequest())
            {
                //Ajax request doesn't return to login page, it just returns 403 error.
                filterContext.Result = new HttpAuthorizeFailedResult();
            }
            else
                base.HandleUnauthorizedRequest(filterContext);
        }
    }

嗨,Sergei。感谢您的回复 - 但我已经创建了自定义的Authorize属性,并且它运行良好。我只需要能够在每个区域中传递适当的角色。我不想在每个控制器上都放置属性。我正在寻找一些可以在某人添加新区域时自动设置的东西。 - Saan
看看我是怎么做的。AjaxRole变量被传递到自定义AuthorizeAttribute中。自动化可能有点困难,但在函数头部添加[AjaxAuthorize(AjaxRole = "Administrators")]并不难,可以解决你的问题。 - Sergei Golos
但这意味着任何添加代码到项目中的人(其中一些将是第三方开发人员)都需要确保正确的Authorize属性已添加到控制器中。我正在寻找的是一种方法,无论如何都可以确保使用正确的授权。 - Saan
这种方式是否包含了其他人必须遵循的命名约定?我的意思是,你比我更清楚自己需要什么,但这是微软推荐使用AuthorizeAttribute的方式。 - Sergei Golos
并不是真的 - 当我添加第三方区域时 - 其中一部分将是添加角色。我认为,如果我可以获取站点中所有区域的列表,然后循环遍历它们,那么它会起作用。 - Saan

-1

当我在调查一个单独的问题时,我偶然发现了如何在ASP.NET MVC 2中将参数传递给自定义ActionFilter?

那个属性示例可以修改为检查当前控制器的区域。

public class CustomAuthorizeAttribute : AuthorizeAttribute
{
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        RouteData routeData = filterContext.RouteData;

        // check if user is allowed on this page
        if (SessionFactory.GetSession().Contains(SessionKey.User))
        {
            User user = (User)SessionFactory.GetSession().Get(SessionKey.User);
            string thisArea = routeData.DataTokens["area"].ToString();

            // if the user doesn't have access to this area
            if (!user.IsInRole(thisArea))
            {
                HandleUnauthorizedRequest(filterContext);
            }
        }

        // do normal OnAuthorization checks too
        base.OnAuthorization(filterContext);
    }
}

我然后在Global.asax中将我的自定义授权属性应用于所有控制器,像这样:

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
    filters.Add(new HandleErrorAttribute());
    // for all controllers, run CustomAuthorizeAttribute to make sure they're at logged in and have access to area
    filters.Add(ObjectFactory.GetInstance<CustomAuthorizeAttribute>());
}

感谢所有回复的人

Saan


1
警告:这不是安全的做法。我一直在研究同一个领域,并发现这不是一个可取的做法。区域是一个路由的概念,但即使没有指定该区域,也可以找到并选择控制器。Levi在这里解释 - Quango

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接