Различение действий контроллера с использованием фильтров авторизации - PullRequest
2 голосов
/ 05 марта 2010

Я хотел бы иметь 4 действия с одинаковым именем (методы контроллера могут иметь другое имя, но их атрибут ActionName() одинаков для всех 4 из них:

[ActionName("Same-name")]
public ActionResult AnonAction() { ... }

[HttpPost]
[ActionName("Same-name")]
public ActionResult AnonAction(ModelData data) { ... }

[Authorize]
[ActionName("Same-name")]
public ActionResult AuthAction() { ... }

[HttpPost]
[Authorize]
[ActionName("Same-name")]
public ActionResult AuthAction(OtherData data) { ... }

Первая пара что-то делает, когда пользователи не аутентифицированы (анонимные пользователи). Вторая пара делает нечто подобное (но не то же самое), когда пользователи проходят проверку подлинности .

Первые три метода действия работают, как и ожидалось, но я не могу заставить последний работать. Это вызывает исключение, говорящее мне, что он не может различить действия POST. Я не думаю, что я сделал что-то не так или забыл что-то сделать. Я просто надеюсь, что это не ошибка в Asp.net MVC 2 RC2.

Кто-нибудь видит недостатки в моих действиях?

Ответы [ 2 ]

3 голосов
/ 05 марта 2010

@ Пако прав. AuthorizeAttribute не имеет ничего общего с выбором действия. Его предложение не было правильным, поэтому благодаря ему я немного покопался в коде MVC и сам придумал наиболее подходящее решение.

Решение, как и предполагалось

В MVC есть точка расширяемости для этих вещей. По сути, вам нужно написать собственный ActionMethodSelectionAttribute, который справится с этим. Я создал один, который выбирает действие на основе авторизации пользователя (анонимного или авторизованного). Вот код:

/// <summary>
/// Attribute restricts controller action execution only to either anonymous or authenticated users
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public class AllowAuthenticatedAttribute : ActionMethodSelectorAttribute
{
    /// <summary>
    /// Gets or sets a value indicating whether this <see cref="AllowAuthorizedAttribute"/> allows authenticated or anonymous users to execute decorated controller action.
    /// </summary>
    /// <value><c>true</c> if authenticated users are allowed to execute the action; <c>false</c> if anonymous users are allowed to execute the action.</value>
    public bool Authenticated { get; set; }

    /// <summary>
    /// Initializes a new instance of the <see cref="AllowAuthorizedAttribute"/> class.
    /// </summary>
    /// <param name="authenticated">If set to <c>true</c> only authorized users will be able to access this action.</param>
    public AllowAuthenticatedAttribute(bool authenticated)
    {
        this.Authenticated = authenticated;
    }

    /// <summary>
    /// Determines whether the action method selection is valid for the specified controller context.
    /// </summary>
    /// <param name="controllerContext">The controller context.</param>
    /// <param name="methodInfo">Information about the action method.</param>
    /// <returns>
    /// true if the action method selection is valid for the specified controller context; otherwise, false.
    /// </returns>
    public override bool IsValidForRequest(ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo)
    {
        if (controllerContext == null)
        {
            throw new ArgumentNullException("controllerContext");
        }
        return this.Authenticated == controllerContext.HttpContext.User.Identity.IsAuthenticated;
    }
}

Дополнительное наблюдение

Когда я украсил свои методы действий своим пользовательским атрибутом, я все еще получал то же исключение, пока не добавил [HttpGet] к своим действиям GET. Это почему? Я нашел ответ в блок-схеме в Pro ASP.NET MVC Framework книга ( проверить его самостоятельно ). Было сгенерировано исключение, потому что было более одного метода действия с ActionMethodSelectorAttribute. Обычно мы просто украшаем POST-действия, но в этом случае все они были оформлены. 2 для анонимных и 2 для аутентифицированных пользователей. Вот почему вы должны использовать оба HttpGet и HttpPost для методов действия при добавлении к ним дополнительных атрибутов селектора.

Действия моего контроллера теперь выглядят так

[HttpGet]
[AllowAuthenticated(false)]
[ActionName("Same-name")]
public ActionResult AnonAction() { ... }

[HttpPost]
[AllowAuthenticated(false)]
[ActionName("Same-name")]
public ActionResult AnonAction(ModelData data) { ... }

[HttpGet]
[Authorize]
[AllowAuthenticated(true)]
[ActionName("Same-name")]
public ActionResult AuthAction() { ... }

[HttpPost]
[Authorize]
[AllowAuthenticated(true)]
[ActionName("Same-name")]
public ActionResult AuthAction(OtherData data) { ... }
2 голосов
/ 05 марта 2010

Необходимо создать ограничение маршрута для авторизованных и неавторизованных действий. System.Web.Routing ничего не делает с атрибутом authorize.

...