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

发布于 2024-08-24 02:28:18 字数 654 浏览 4 评论 0 原文

我想要 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 中的错误

有人看到我的操作有任何缺陷吗?

I would like to have 4 actions with the same name (controller methods may have a different name, but their ActionName() attribute is the same for all 4 of them:

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

The first couple does something when users are not authenticated (anonymous users). The second couple does something similar (but not the same) when users are authenticated.

First three action methods work as expected, but I can't seem to make the last one work. It throws an exception telling me, that it can't distinguish between POST actions. I don't think I've made anything wrong here or forgotten to do something. I just hope it's nto a bug in Asp.net MVC 2 RC2.

Does anyone see any flaw in my actions?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

十年九夏 2024-08-31 02:28:18

@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一书中的流程图中找到了答案(自己检查一下)。抛出异常是因为 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) { ... }

@Paco is right. AuthorizeAttribute doesn't have anything to do with action selection. His suggestion didn't feel right so thanks to him I did some digging into MVC code and I came up with the most appropriate solution myself.

Solution as it was meant to be

There's an extensibility point for these things in MVC. Basically what you have to do is to write you own ActionMethodSelectionAttribute that will handle this. I created one that selects action based on user authorization (either anonymous or authorized). Here's the code:

/// <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;
    }
}

Additional observation

When I decorated my action methods with my custom attribute I still got the same exception until I added [HttpGet] to my GET actions. Why is that? I found the answer in the flowchart in Pro ASP.NET MVC Framework book (check it out yourself). Exception was thrown because there were more than just one action method with ActionMethodSelectorAttribute. Normally we just decorate out POST actions, but in this case all of them were decorated. 2 for anonymous and 2 for authenticated users. That's why you have to use both HttpGet and HttpPost on action methods when you add more selector attributes to them.

My controller actions now look like this

[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) { ... }
甩你一脸翔 2024-08-31 02:28:18

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

You have to create a route constraint for the authorized and non authorized actions. System.Web.Routing is not doing anything with the authorize attribute.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文