1

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

我在想的是向我扩展的 AuthorizeAttribute 类添加 EntityProperty、UserProperty、RouteParameter 和 JoinTableType 参数。前两个将是连接表中要检查的属性的名称。RouteParameter 将是要为要匹配的 EntityProperty 的值提取的路由参数的名称。我会使用当前用户名从用户表中获取用户 ID。JoinTableType 参数将是数据上下文中表的类型,其中包含路由参数值和用户 ID 必须匹配的实体和用户属性。

基本思想是,在伪代码中:

 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反思来完成这一切。我真的在寻找有关如何使这更容易的想法,因此其他建议也会受到赞赏。我更喜欢使用该属性,而不是将检查直接嵌入到操作中,以使其与我处理其他操作的方式保持一致。

4

1 回答 1

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;
    }
}
于 2009-01-15T20:06:01.443 回答