2009-01-15 117 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; 
    } 
}