6

I have an action I want to restrict only to role "Admin". I did it like this:

[Authorize(Roles = "Admin")]
public ActionResult Edit(int id)

After manually going under Controller/Edit/1 path I'm redirected to login page. Well, that isn't bad maybe, but I want to show 404 instead of it and try to stick using attributes for it. Is that possible?

deha
  • 805
  • 8
  • 29
  • 3
    Just a comment, perhaps you should show a 401 or 403 http://en.wikipedia.org/wiki/List_of_HTTP_status_codes#4xx_Client_Error – Danny Feb 29 '12 at 17:12
  • 1
    oh, formally you're right, but I don't want others to know that the action name is correct (that would probably suggest it) – deha Feb 29 '12 at 17:14
  • I believe this is a duplicate of [Asp.net MVC Authorize attribute, redirect to custom “no rights” page](http://stackoverflow.com/q/4457476/267448) – Brian Rogers Feb 29 '12 at 17:15
  • Duplicate or not, Darin's answer is a good one that I don't think I've seen before. – Brian Rogers Feb 29 '12 at 17:27

2 Answers2

14

Is that possible?

Sure, you could write a custom authorize attribute:

public class MyAuthorizeAttribute : AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        filterContext.Result = new ViewResult
        {
            ViewName = "~/Views/Shared/401.cshtml"
        };
    }
}

and then use it:

[MyAuthorize(Roles = "Admin")]
public ActionResult Edit(int id)

Remark: you probably want to show a 401 or 403 page if the user is not authorized instead of 404 which is for file not found.

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • It may be helpful for others to know that this may be combined with another of [Darin's answers](http://stackoverflow.com/questions/5314673/user-is-in-role-admin-but-authorizeroles-admin-wont-authenticate). I have done just that and it works brilliantly. To combine the two include the `HandleUnauthorizedRequest` method from this answer in the same class as the `OnAuthorization` method from the other answer. Keep up the good work Darin! – Ben Jul 04 '12 at 12:06
  • @Ben can you share your solution? – Daniel Jul 11 '14 at 14:03
  • @Daniel I can try! It's been 2 years since I looked at this code but I'll do a new answer in a minute. – Ben Jul 11 '14 at 15:10
1

In response to @Daniel's comment on my comment to @Darin's answer this is my implementation:

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        string cookieName = FormsAuthentication.FormsCookieName;

        if (!filterContext.HttpContext.User.Identity.IsAuthenticated ||
            filterContext.HttpContext.Request.Cookies == null ||
            filterContext.HttpContext.Request.Cookies[cookieName] == null
        )
        {
            HandleUnauthorizedRequest(filterContext);
            return;
        }

        var authCookie = filterContext.HttpContext.Request.Cookies[cookieName];
        var authTicket = FormsAuthentication.Decrypt(authCookie.Value);
        string[] roles = authTicket.UserData.Split(',');

        var userIdentity = new GenericIdentity(authTicket.Name);
        var userPrincipal = new GenericPrincipal(userIdentity, roles);

        filterContext.HttpContext.User = userPrincipal;
        base.OnAuthorization(filterContext);
    }

    // Redirects unauthorized users to a "401 Unauthorized" page
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        filterContext.Result = new ViewResult
        {
            ViewName = "~/Views/Shared/Error/401.cshtml"
        };
    }
}
Ben
  • 5,525
  • 8
  • 42
  • 66