How to use custom Authorize attribute for roles as well as a specific user?
Solution 1
You could write a custom authorize attribute:
public class AuthorizeAdminOrOwnerOfPostAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var authorized = base.AuthorizeCore(httpContext);
if (!authorized)
{
// The user is not authenticated
return false;
}
var user = httpContext.User;
if (user.IsInRole("Admin"))
{
// Administrator => let him in
return true;
}
var rd = httpContext.Request.RequestContext.RouteData;
var id = rd.Values["id"] as string;
if (string.IsNullOrEmpty(id))
{
// No id was specified => we do not allow access
return false;
}
return IsOwnerOfPost(user.Identity.Name, id);
}
private bool IsOwnerOfPost(string username, string postId)
{
// TODO: you know what to do here
throw new NotImplementedException();
}
}
and then decorate your controller action with it:
[AuthorizeAdminOrOwnerOfPost]
public ActionResult EditPosts(int id)
{
return View();
}
Solution 2
I understand that you have already accepted an answer, and this was posted a while back.. (btw:excellent answer for adding custom attributes), However I would point out the following:
If you are using this attribute once. On a Single method. This isn't a good implementation. Instead you should have:
[Authorize] // Just make sure they are auth'ed at all.
public ActionResult EditPosts(int id)
{
Post SomePost = findPostByID (id); // However you do it - single lookup of post
if (!user.IsInRole("Admin") && !{IsOwnerOfPost(post)} ) Return Not Authorized
... Edit post code here
}
This has the advantages of:
- No additional class that someone will later wonder where it is used.
- No class that isn't usable anywhere else (you don't gain reuse with a custom attribute)
- Performance is better: Single fetch of the Post
- Way easier for someone to read/figure out how it works. No magic code to track down.
- And Years later, when HttpContextBase class doesn't exist, or other parts of the tricks used to fetch the Id parameter are gone, the code still works...
Freeman
C# \ .NET Developer, Silverlight, WPF, Windows Phone, ASP.NET MVC, SQL Server, Windows Server, and other .NET stuff while trying to keep in mind clean and optimized code. Also a bit of a C++ amateur as well.
Updated on July 31, 2020Comments
-
Freeman almost 4 years
I have my Action Method
[Authorize(Roles="Admin")] public ActionResult EditPosts(int id) { return View(); }
In my case I need to authorize administrators so they can edit posts but (here comes the cool part), I also need to allow the creator of the post to be able to edit the post which is a normal user. So how can I filter out the user that created the post as well as the admins but leave the others unauthorized? I am receiving the PostEntry id as a route parameter but that's after the attribute and also attributes only accept constant parameters, looks like something very difficult, your answers are highly appreciated, Cheers!
-
Royi Namir over 9 yearsWhy // Now id was specified => we do not allow access ?
-
Royi Namir over 9 yearsNow I see you need to change : // Now id was specified to NO id was specified....(it seems that if there is ID we dont allow access)
-
cyclical about 9 yearsThank you -- cuts through the flak that is out there and gets right to the point!
-
Sorangwala Abbasali over 7 yearsThis post is very useful as it helped me to make possible to allow all the roles in the mvc application except the "user" role for some controller.