8

本质上,当某人不属于我的属性中列出的角色时,我想显示一条友好的消息。目前我的应用程序只是将用户吐回登录屏幕。我已经阅读了一些关于创建仅扩展 [AuthorizeAttribute] 的自定义属性的帖子,但我认为必须有一些开箱即用的东西才能做到这一点?

有人可以请我指出我需要寻找的正确方向,不要让它将用户发送到登录表单,而只是向他们发送“未授权”消息?

4

5 回答 5

6

我添加 $0.02 可能有点晚,但是当您创建 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: ...
}
于 2010-08-30T20:26:54.423 回答
3

几天前我遇到了这个问题,解决方案有点详细,但这里是重要的部分。在AuthorizeAttributeOnAuthorization方法中,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;以启用您的自定义错误。

于 2010-01-07T21:10:54.193 回答
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...)

于 2010-01-07T18:50:05.443 回答
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);
        }
    }
}
于 2011-05-13T17:20:42.463 回答
0

开箱即用的行为是 [Authorize] 属性返回 HTTP 401。FormsAuthenticationModule(默认加载)拦截此 401 并将用户重定向到登录页面。看看 System.Web.Security.FormsAuthenticationModule::OnLeave in Reflector 看看我的意思。

如果您希望 AuthorizeAttribute 执行返回 HTTP 401 以外的操作,则必须覆盖 AuthorizeAttribute::HandleUnauthorizedRequest 方法并在其中执行您的自定义逻辑。或者,只需更改 ~\Web.config 的这一部分:

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

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

于 2010-01-07T19:35:39.360 回答