.NET MVC控制器操作方法的属性

9

我希望当某人不属于我的属性列表中的角色时,能够显示友好的消息。目前,我的应用程序只会将用户弹回登录界面。我读了一些帖子,讨论了创建一个自定义属性,仅扩展[AuthorizeAttribute],但我认为肯定有一些开箱即用的东西可以做到这一点吧?

请问有人可以指导我应该去哪里查找,以便不要将用户发送到登录表单,而是直接向他们发送“未经授权”的消息?

5个回答

6

可能有点晚了,但是当你创建自定义的CustomAuthorizationAttribue时,可以使用AuthorizationContext.Result属性来指定AuthorizeAttribute.HandleUnauthorizedRequest方法将用户重定向到何处。

这里有一个非常简单的示例,允许您指定在授权失败后应将用户发送到的URL:

public class Authorize2Attribute : AuthorizeAttribute
{
    // Properties

    public String RedirectResultUrl { get; set; }

    // Constructors

    public Authorize2Attribute()
        : base()
    {
    }

    // Overrides

    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        if (String.IsNullOrEmpty(RedirectResultUrl))
            base.HandleUnauthorizedRequest(filterContext);

        else
            filterContext.Result = new RedirectResult(RedirectResultUrl);
    }
}

如果我想像之前的帖子所建议的那样将用户重定向到 /Error/Unauthorized,应该怎么做:

[Authorize2(Roles = "AuthorizedUsers", RedirectResultUrl = "/Error/Unauthorized")]
public ActionResult RestrictedAction()
{
    // TODO: ...
}

我做过类似的事情,但是我会检查用户是否已经通过身份验证。这样可以让我拒绝那些没有角色身份的用户,但是他们不需要重新登录。 - Nick Randell

3
我几天前遇到了这个问题,解决方案有点详细,但以下是重要的部分。在AuthorizeAttribute中,当授权失败时,OnAuthorization方法会返回HttpUnauthorizedResult,这使得返回自定义结果变得有些困难。
我最终做的是创建一个CustomAuthorizeAttribute类,并覆盖OnAuthorization方法,改为抛出异常。然后,我可以使用自定义错误处理程序捕获该异常,并显示自定义的错误页面,而不是返回401(未经授权)。
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
    public virtual void OnAuthorization(AuthorizationContext filterContext) {
        if (filterContext == null) {
            throw new ArgumentNullException("filterContext");
        }

        if (AuthorizeCore(filterContext.HttpContext)) {
            HttpCachePolicyBase cachePolicy = filterContext.HttpContext.Response.Cache;
            cachePolicy.SetProxyMaxAge(new TimeSpan(0));
            cachePolicy.AddValidationCallback(CacheValidateHandler, null /* data */);
        }
        else {
            // auth failed, redirect to login page
            // filterContext.Result = new HttpUnauthorizedResult();

            throw new HttpException ((int)HttpStatusCode.Unauthorized, "Unauthorized");                
        }
    }
}

然后,在您的web.config文件中,您可以为特定错误设置自定义处理程序:

    <customErrors mode="On" defaultRedirect="~/Error">
        <error statusCode="401" redirect="~/Error/Unauthorized" />
        <error statusCode="404" redirect="~/Error/NotFound" />
    </customErrors>

然后实现自己的ErrorController来提供自定义页面。

在IIS7上,您需要设置Response.TrySkipIisCustomErrors = true;来启用自定义错误。


2
如果您想要简单或完全控制逻辑,您可以在您的操作方法中调用此方法:
User.IsInRole("NameOfRole");

它返回一个布尔值,您可以根据该结果执行其他逻辑。

另一个我在某些情况下使用的是:

System.Web.Security.Roles.GetRolesForUser();

我认为这会返回一个字符串数组,但请勿引用我说的话。
编辑:一个例子总是有帮助的...
public ActionResult AddUser()
{
    if(User.IsInRoles("SuperUser")
    {
        return View("AddUser");
    }
    else
    {
        return View("SorryWrongRole");
    }
}

只要你的返回类型是“ActionResult”,你就可以返回任何被接受的返回类型(ViewResult、PartialViewResult、RedirectResult、JsonResult...)。

那么按照这个逻辑,我需要使用“友好信息”返回部分视图,对吗?难道不可能用一个属性来包含整个操作方法并执行同样的操作吗? - Kyle
我在上面添加了一个例子。你当然可以像你提到的那样编写自己的属性(这将是最干净的选择,尽管更难进行单元测试),但这绝对不是一个开箱即用的方法。 - DM.

2

与crazyarabian非常相似,但我只在用户已经通过身份验证时才将其重定向到我的字符串。这允许属性在用户未登录时重定向到标准登录页面,但如果他们没有权限访问url,则重定向到另一个页面。

public class EnhancedAuthorizeAttribute : AuthorizeAttribute
{
    public string UnauthorizedUrl { get; set; }

    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        var redirectUrl = UnauthorizedUrl;
        if (filterContext.HttpContext.User.Identity.IsAuthenticated && !string.IsNullOrWhiteSpace(redirectUrl))
        {
            filterContext.Result = new RedirectResult(redirectUrl);
        }
        else
        {
            base.HandleUnauthorizedRequest(filterContext);
        }
    }
}

0

默认情况下,[Authorize] 属性的行为是返回 HTTP 401。FormsAuthenticationModule(默认加载)拦截此 401 并将用户重定向到登录页面。请查看 Reflector 中的 System.Web.Security.FormsAuthenticationModule::OnLeave。

如果您希望 AuthorizeAttribute 做一些其他事情而不是返回 HTTP 401,则必须覆盖 AuthorizeAttribute::HandleUnauthorizedRequest 方法,并在其中执行自定义逻辑。或者,只需更改 ~\Web.config 的此部分:

<forms loginUrl="~/Account/LogOn" timeout="2880" />

并将其指向不同的URL,例如~/AccessDenied。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接