ASP.Net MVC: можно ли переопределить атрибут AuthorizeAttribute? - PullRequest
2 голосов
/ 10 февраля 2009

Мой текущий проект - это внутреннее веб-приложение, созданное с использованием ASP.Net MVC, к которому я добавляю аутентификацию. У меня есть встроенный HTTPModule, который создает IPrincipal с соответствующими ролями. Если пользователь не аутентифицирован, я получаю объект пользователя с ролью «Public»

Поскольку это внутреннее приложение, большинство страниц являются закрытыми и доступны для просмотра только роли «Администратор». Поскольку у меня есть базовый контроллер, я могу сделать это:

[Authorize(Roles="Admin")]
public abstract class MyControllerBase : Controller
{
    ...
}

У меня есть проблема, хотя некоторые действия доступны для просмотра на общедоступном веб-сайте, и если я их приписываю следующим образом:

[Authorize(Roles="Public")]
public class LoginController : MyController
{
    public ActionResult Index()
    {

    }
}

Страница не загружается, поскольку пользователь не аутентифицирован. Казалось бы, роль «Public» игнорируется в унаследованном классе. Кто-нибудь знает, могут ли роли быть переопределены унаследованными классами?

Я также пытаюсь избежать присвоения всем контроллерам ролей = "Admin"

Спасибо, Кит.

Ответы [ 2 ]

6 голосов
/ 10 февраля 2009

Вы можете получить новый атрибут из AuthorizeAttribute и переопределить метод OnAuthorization, а затем применить свой настраиваемый атрибут вместо Authorize. Ниже приведен метод OnAuthorization из одного из моих настраиваемых атрибутов, который перенаправляет на страницу ошибки, если привилегий недостаточно, вместо перенаправления на страницу входа.

Я не уверен точно, что это купит тебя, хотя. Когда вы украшаете свой класс атрибутом, по-видимому, вам нужно будет разрешить и Admin, и Public (так кого вы ограничиваете, так как Public - это тот, кто не аутентифицирован?). Затем вам нужно будет украсить каждый из методов контроллера, который должен быть ограничен только для администратора, так как атрибут класса разрешит доступ в противном случае. Вы можете добиться такого поведения с помощью обычного атрибута Authorize, просто декорируя только те, которые не являются общедоступными методами (или классы, которые не имеют общедоступных методов).

Я полагаю, что вы могли бы проверить свой атрибут, чтобы увидеть, украшен ли вызываемый метод атрибутом, и просто утвердить авторизацию, которая фактически отложит авторизацию до уровня метода. Возможно, вам придется заглянуть в RouteData на AuthorizationContext, чтобы получить действие и использовать отражение, чтобы попытаться найти подходящий метод на основе параметров и типа запроса.

    public override void OnAuthorization( AuthorizationContext filterContext )
    {
        if (filterContext == null)
        {
            throw new ArgumentNullException( "filterContext" );
        }

        if (AuthorizeCore( filterContext.HttpContext ))
        {
            SetCachePolicy( filterContext );
        }
        else if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
        {
            // auth failed, redirect to login page
            filterContext.Result = new HttpUnauthorizedResult();
        }
        else
        {
            ViewDataDictionary viewData = new ViewDataDictionary();
            viewData.Add( "Message", "You do not have sufficient privileges for this operation." );
            filterContext.Result = new ViewResult { MasterName = this.MasterName, ViewName = this.ViewName, ViewData = viewData };
        }

    }

    protected void SetCachePolicy( AuthorizationContext filterContext )
    {
        // ** IMPORTANT **
        // Since we're performing authorization at the action level, the authorization code runs
        // after the output caching module. In the worst case this could allow an authorized user
        // to cause the page to be cached, then an unauthorized user would later be served the
        // cached page. We work around this by telling proxies not to cache the sensitive page,
        // then we hook our custom authorization code into the caching mechanism so that we have
        // the final say on whether a page should be served from the cache.
        HttpCachePolicyBase cachePolicy = filterContext.HttpContext.Response.Cache;
        cachePolicy.SetProxyMaxAge( new TimeSpan( 0 ) );
        cachePolicy.AddValidationCallback( CacheValidateHandler, null /* data */);
    }
5 голосов
/ 11 февраля 2009

Ну, в конце концов, я думаю, что мой ответ был в вопросе. Вместо того, чтобы помещать атрибут Authorize в мой базовый контроллер, я получил новый AdminBaseController.

[HandleError]
public abstract class MyControllerBase : Controller
{
    ...
}

[Authorize(Roles="Admin")]
public abstract class AdminControllerBase : MyControllerBase
{
    ....
}

Теперь любые контроллеры, требующие аутентификации, могут быть получены из AdminControllerBase, а мои публичные контроллеры - из MyControllerBase. ОО на помощь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...