使用授权过滤器区分控制器操作

时间:2010-03-04 22:08:04

标签: asp.net-mvc asp.net-mvc-2 filter controller action

我希望有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 个答案:

答案 0 :(得分:3)

@Paco是对的。 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 一书(check it out yourself)的流程图中找到了答案。抛出了异常,因为ActionMethodSelectorAttribute只有一个动作方法。通常我们只是装饰POST动作,但在这种情况下,所有这些都被装饰了。 2表示匿名用户,2表示经过身份验证的用户。这就是为什么当您向其添加更多选择器属性时必须同时使用HttpGetHttpPost操作方法

我的控制器操作现在看起来像这样

[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) { ... }

答案 1 :(得分:2)

您必须为授权和非授权操作创建路由约束。 System.Web.Routing没有对authorize属性做任何事情。