ASP.NET MVC Авторизация на основе членства в роли или связи данных (владение) - PullRequest
1 голос
/ 15 января 2009

Я бы хотел расширить атрибут AuthorizeAttribute в ASP.NET MVC, чтобы он поддерживал концепцию авторизации пользователя, основанную на членстве в его роли ИЛИ "владении" данными данными. Я использую LINQ2SQL для доступа к данным. Есть похожий вопрос при авторизации asp.net mvc с использованием ролей .

Что я думаю, так это добавление параметров EntityProperty, UserProperty, RouteParameter и JoinTableType в мой расширенный класс AuthorizeAttribute. Первые два будут именами свойств в соединяемой таблице для проверки. RouteParameter будет именем параметра маршрута, который нужно извлечь, чтобы значение EntityProperty соответствовало. Я бы получил идентификатор пользователя из таблицы пользователя, используя текущее имя пользователя. Параметр JoinTableType будет типом таблицы в текстовом тексте, который содержит 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 Ответ

1 голос
/ 15 января 2009

Мне удалось использовать расширения Dynamic Linq из образцов VS2008, чтобы сделать это довольно разумным способом. Вот код, представляющий второй пример псевдокода сверху. Он проходит мой первоначальный модульный тест, но мне нужно сделать его более надежным.

Использование:

[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;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...