.net MVC控制器动作方法的属性

时间:2010-01-07 18:25:43

标签: asp.net-mvc authentication membership-provider roleprovider

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

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

5 个答案:

答案 0 :(得分:6)

我可能会稍微添加我的$ 0.02,但是当您创建CustomAuthorizationAttribue时,可以使用AuthorizationContext.Result property来指示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: ...
}

答案 1 :(得分: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 :(得分:2)

如果你想要简单或完全控制逻辑,你可以在你的动作方法中调用它:

User.IsInRole("NameOfRole");

它返回一个bool,你可以根据结果完成其余的逻辑。

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

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

我认为这会返回一个字符串[],但不要引用我。

修改 一个例子总是有帮助...

public ActionResult AddUser()
{
    if(User.IsInRoles("SuperUser")
    {
        return View("AddUser");
    }
    else
    {
        return View("SorryWrongRole");
    }
}

只要您的返回类型为“ActionResult”,您就可以返回任何接受的返回类型(ViewResult,PartialViewResult,RedirectResult,JsonResult ......)

答案 3 :(得分: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);
        }
    }
}

答案 4 :(得分:0)

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

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

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

并指向其他网址,例如〜/ AccessDenied。