2009-01-15 111 views
1

我想在ASP.NET MVC中扩展AuthorizeAttribute,以便它支持基于角色成员身份或用户授权的用户授权概念“有问题的数据。我正在使用LINQ2SQL进行数据访问。在asp.net mvc authorization using roles有类似的问题。ASP.NET MVC基于角色成员身份或数据关系的授权

我在想什么是将EntityProperty,UserProperty,RouteParameter和JoinTableType参数添加到我的扩展AuthorizeAttribute类。前两个将是连接表中要检查的属性的名称。 RouteParameter将是要为要匹配的EntityProperty的值提取的路由参数的名称。我会使用当前用户名从用户表中获取用户标识。 JoinTableType参数应该是datacontext中包含路由参数值和用户标识必须匹配的实体和UserProperties的表的类型。

的基本思路是,在伪代码:

if authorizecore result is true 
    user is granted access based on role 
else if user is not authenticated 
    redirect to logon 
else if user is related to request 
    user is granted access based on relation 
else 
    user is not authorized, redirect to not authorized error view 

的被测试看起来像有关:

result = false 
find the matching user from user name 
find the entity property value in route data 
if user exists and entity property value exists 
    get table from context matching join table type 
    if table exists 
     find row in table matching user id and entity property value 
     if row exists 
      result = true 
     endif 
    endif 
endif 


return result 

我的问题是我怎么在构建LINQ使用类型和属性名查询?或者我将不得不通过object和反思来完成这一切。我真的在寻找关于如何使这更容易的想法,所以其他建议也将被赞赏。我更喜欢使用属性,而不是直接在动作中嵌入检查,以保持与我如何处理其他动作一致。

回答

1

我能够使用VS2008示例中的动态Linq扩展以相当合理的方式执行此操作。这是代表上面第二个伪代码示例的代码。它通过了我最初的单元测试,但我需要使它更加健壮。

用法:

[RoleOrMemberAuthorization(UserTable = "Participants", 
          UserNameProperty = "UserName", 
          UserSelectionProperty = "ParticipantID", 
          JoinTable = "GroupLeaders", 
          EntityProperty = "GroupID", 
          UserEntityProperty = "ParticipantID", 
          RouteParameter = "id", 
          Roles = "SuperUser, ViewGroups")] 

调用为:

else if (IsRelated(filterContext, 
        this.GetTable(dc, this.JoinTable), 
        this.GetTable(dc, this.UserTable))) 
{ 
    SetCachePolicy(filterContext); 
} 

相关源:

protected bool IsRelated(AuthorizationContext filterContext, 
          IQueryable joinTable, 
          IQueryable userTable) 
{ 
    bool result = false; 
    try 
    { 
     object entityIdentifier = filterContext.RouteData 
               .Values[this.RouteParameter]; 
     object userIdentifier = this.GetUserIdentifer(filterContext, userTable); 
     if (userIdentifier != null && entityIdentifier != null) 
     { 
      result = joinTable.Where(this.EntityProperty + "[email protected] and " 
             + this.UserEntityProperty + "[email protected]", 
             entityIdentifier, 
             userIdentifier) 
           .Count() > 0; 
     } 
    } 
    catch (NullReferenceException) { } 
    return result; 
} 

private object GetUserIdentifer(AuthorizationContext filterContext, 
           IQueryable userTable) 
{ 
    string userName = filterContext.HttpContext.User.Identity.Name; 

    var query = userTable.Where(this.UserNameProperty + "[email protected]", userName) 
         .Select(this.UserSelectionProperty); 

    object userIdentifer = null; 
    foreach (var value in query) 
    { 
     userIdentifer = value; 
     break; 
    } 
    return userIdentifer; 
} 

private IQueryable GetTable(DataContext context, string name) 
{ 
    PropertyInfo info = context.GetType().GetProperty(name); 
    if (info != null) 
    { 
     return info.GetValue(context, null) as IQueryable; 
    } 
    else 
    { 
     return null; 
    } 
}