Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

attribute for .net MVC controller action method

Essentially I want to show a friendly message when someone is not part of a role listed in my attribute. Currently my application just spits the user back to the log in screen. I've read a few posts that talk about creating a custom attribute that just extends [AuthorizeAttribute], but I'm thinking there's got to be something out of the box to do this?

can someone please point me in the right direction of where I need to look to not have it send the user to the log in form, but rather just shoot them a "not authorized" message?

like image 914
Kyle Avatar asked Jan 07 '10 18:01

Kyle


3 Answers

I might be a little late in adding my $0.02, but when you create your CustomAuthorizationAttribue, you can use the AuthorizationContext.Result property to dictate where the AuthorizeAttribute.HandleUnauthorizedRequest method directs the user.

Here is a very simple example that allows you to specify the URL where a user should be sent after a failed authorization:

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

And if I wanted to redirect the user to /Error/Unauthorized as suggested in a previous post:

[Authorize2(Roles = "AuthorizedUsers", RedirectResultUrl = "/Error/Unauthorized")]
public ActionResult RestrictedAction()
{
    // TODO: ...
}
like image 109
crazyarabian Avatar answered Sep 28 '22 06:09

crazyarabian


I ran into this issue a few days ago and the solution is a bit detailed but here are the important bits. In AuthorizeAttribute the OnAuthorization method returns a HttpUnauthorizedResult when authorization fails which makes returning a custom result a bit difficult.

What I ended up doing was to create a CustomAuthorizeAttribute class and override the OnAuthorization method to throw an exception instead. I can then catch that exception with a custom error handler and display a customized error page instead of returning a 401 (Unauthorized).

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");                
        }
    }
}

then in your web.config you can set custom handlers for specific errors:

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

and then implement your own ErrorController to serve up custom pages.

On IIS7 you need to look into setting Response.TrySkipIisCustomErrors = true; to enable your custom errors.

like image 23
Todd Smith Avatar answered Sep 28 '22 08:09

Todd Smith


If simplicity or total control of the logic is what you want you can call this in your action method:

User.IsInRole("NameOfRole");

It returns a bool and you can do the rest of your logic depending on that result.

Another one that I've used in some cases is:

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

I think that returns a string[] but don't quote me on that.

EDIT: An example always helps...

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

As long as your return type is "ActionResult" you could return any of the accepted return types (ViewResult, PartialViewResult, RedirectResult, JsonResult...)

like image 38
DM. Avatar answered Sep 28 '22 08:09

DM.