我想在ASP.NET MVC中扩展AuthorizeAttribute,以便它支持用户授权的概念,该授权基于他们的角色成员资格或所讨论数据的“所有权”。我正在使用LINQ2SQL进行数据访问。 asp.net mvc authorization using roles也有类似的问题。
我在想的是将EntityProperty,UserProperty,RouteParameter和JoinTableType参数添加到扩展的AuthorizeAttribute类中。前两个是要检查的连接表中属性的名称。 RouteParameter将是要提取的EntityProperty值匹配的路由参数的名称。我使用当前用户名从用户表中获取用户ID。 JoinTableType参数将是datacontext中包含路由参数值和用户ID必须匹配的Entity和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
和反思做所有这些。我正在寻找如何使这更容易的想法,所以其他建议也将受到赞赏。我更喜欢使用该属性,而不是直接将检查嵌入到操作中,以使其与我处理其他操作的方式保持一致。
答案 0 :(得分:1)
我能够使用VS2008示例中的Dynamic 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 + "=@0 and "
+ this.UserEntityProperty + "=@1",
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 + "=@0", 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;
}
}