代码之家  ›  专栏  ›  技术社区  ›  tvanfosson

ASP。NET MVC基于角色成员关系或数据关系(所有权)的授权

  •  1
  • tvanfosson  · 技术社区  · 16 年前

    我想扩展ASP。NET MVC,因此它支持用户的授权基于其角色成员资格或所讨论数据的“所有权”的概念。我使用LINQ2SQL进行数据访问。还有一个类似的问题 asp.net mvc authorization using roles .

    我正在考虑将EntityProperty、UserProperty、RouteParameter和JoinTableType参数添加到我的扩展AuthorizeAttribute类中。前两个是要检查的联接表中的属性名称。RouteParameter将是要提取以匹配EntityProperty值的路由参数的名称。我将使用当前用户名从用户表中获取用户id。JoinTableType参数将是数据上下文中包含路由参数值和用户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 和反思。我真的在寻找如何使这更容易的想法,所以其他建议也会受到欢迎。我更喜欢使用该属性,而不是将检查直接嵌入到操作中,以使其与我处理其他操作的方式保持一致。

    1 回复  |  直到 8 年前
        1
  •  1
  •   tvanfosson    16 年前

    我能够使用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;
        }
    }