I have two attributes :
public class AnonymousAllowedAttribute : AuthorizeAttribute { }
public class ActionAuthorizeAttribute : AuthorizeAttribute {
public override void OnAuthorization(AuthorizationContext filterContext) {
bool skipAuthorization =
filterContext.ActionDescriptor.IsDefined(typeof(AnonymousAllowedAttribute), true)
||
filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(AnonymousAllowedAttribute), true);
if(!skipAuthorization)
base.OnAuthorization(filterContext);
}
bool CustomeCheck() {
bool result = //My Checks
return result;
}
}
I define ActionAuthorizeAttribute as a global attribute.
So I need this 3 items:
1- If did not log in(!User.Identity.IsAuthenticated): Go to LogIn Page Accounts/LogIn.
I must mention the LogIn action marked with AnonymousAllowedAttribute.
2- If log in (User.Identity.IsAuthenticated) and action or controller have AnonymousAllowedAttribute then authorize is true (don't need any authorization).
3- If log in (User.Identity.IsAuthenticated) and action haven't AnonymousAllowedAttribute return CustomeCheck() method
I try second one by override OnAuthorization() method as you see.
and third one by followings:
protected override bool AuthorizeCore(System.Web.HttpContextBase httpContext){
if(!httpContext.User.Identity.IsAuthenticated)
return false;
return CustomeCheck();
}
but when I did not log in always return:
IIS 7.5 Error Details:
HTTP Error 401.0 - Unauthorized
with this URL: http://myProject/Accounts/LogIn?ReturnUrl=%2f
where is the problem? how can implement ActionAuthorizeAttribute to achieve this 3 goals?
Update
I find answer : the problem is the : AnonymousAllowedAttribute need to inherit from Attribute rather than AuthorizeAttribute.
the problem is: The AnonymousAllowedAttribute need to inherit from Attribute rather than AuthorizeAttribute.
when AnonymousAllowedAttribute inherit from AuthorizeAttribute so need to authorize but I create that to reduce Authorization!!
Related
I'm using MvcSitemapProvider for my ASP MVC 5 project.
I've implemented a custom Authorize to check if roles from sitemap are equal to users roles.
This is what it looks like:
public class CustomAuthorize : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
bool authorize = false;
var roles = SiteMaps.Current.CurrentNode.Roles;
foreach (var role in roles)
if (System.Web.Security.Roles.IsUserInRole(role))
authorize = true;
return authorize;
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
filterContext.Result = new HttpUnauthorizedResult();
}
}
My issue is that when using SiteMaps.Current.CurrentNode.Roles it throws a An unhandled exception of type 'System.StackOverflowException' occurred in System.Web.dll and I have no clue why. The objects are filled, nothing is null.
Why does this happen? Right now I'm clueless about how to get this to work as a simple currentNode doesn't work...
The default implementation of AuthorizeAttribute is all you need to interact with MvcSiteMapProvider. AuthorizeAttribute already supports roles.
// Only users in the "Manager" role have access to all actions on this controller
[Authorize(Roles = "Manager")]
public class AccountController : Controller
{
public ActionResult Manage()
{
return View();
}
public ActionResult ChangePassword()
{
return View();
}
}
The only thing you need to do is enable security trimming. See the security trimming documentation.
I think the call to current node is generating another request for the page which will again invoke your authorization filter. In other words, this code is creating an infinite loop of calls to itself none of which ever return which is why the call stack is overflowing.
I would store the roles you want to check for in another way.
On my MVC4 internet application I am using the AccountController that comes by default along with roles etc.
So I have this controller in which I have defined roles to access the actions, example below.
public class SomeController : Controller
{
private SomeDbContext db = new LookbookDbContext();
//
// GET: /Default1/
[Authorize(Roles = "Administrator")]
public ActionResult Index()
{
return View(db.SomeTable.ToList());
}
...
}
What I wanted now is that, when a user/anonymous tries to access this Index action, get's a custom error view I have made instead of showing the Login form.
I have added this but it just does nothing. I keep getting the login form page. I changed it, for testing porpuses, to give me the default 401 error page but it doesn't work either.
public class CustomAuthorize : AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
filterContext.Result = new HttpUnauthorizedResult();
}
}
You should just be able to redirect to your custom error view from your attribute.
Example
public class UnAuthorizedRedirectAttribute : AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
filterContext.RequestContext.HttpContext.Response.Redirect("~/error/no-bacon");
}
}
Obviously, the first thing you need to do is make your custom view.
Now, I would reccomend making an action filter to handle this:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class AuthorizeAttribute : System.Web.Mvc.AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(System.Web.Mvc.AuthorizationContext filterContext)
{
if (filterContext.HttpContext.Request.IsAuthenticated)
{
filterContext.Result = new System.Web.Mvc.HttpStatusCodeResult((int)System.Net.HttpStatusCode.Forbidden);
}
else
{
filterContext.RequestContext.HttpContext.Response.Redirect("~/shared/error");
}
}
}
NOTE: This answer was added to the question. I'm moving it here to conform to site guidelines.
What I was missing was the [CustomAuthorize] attribute on my Actions. Once I have added that to the desired action it worked.
I have used [Authorize] attribute a lot in the past, and it allows you to also do things like this:
[Authorize(Users = "test")]
However, I would like to add another one,
[Authorize(IsPermitted= PermissionsEnum.ThePermission)]
I have the logic written out that would decide if the user was permitted for that permission, but I'm not sure how to add that overload to the authorize attribute.
I would prefer not to make a entirely separate authorize attribute if possible.
Well, as #Dave A has said on the comments, you can extend the native Authorize attribute and implement your own authorization method, for sample:
public class MyAuthorizeAttribute : AuthorizeAttribute
{
// create your custom property
public PermissionsEnum IsPermitted { get; set; }
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
bool authorized = // create your own validation and return a bool value
if (authorized)
{
return false;
}
// if you want to have the nativa validation, call it from the base method
return base.AuthorizeCore(httpContext);
}
}
and remember to decorate your controllers/actions with your Custom Authorize Attribute, for sample:
[MyAuthorize(IsPermitted = PermissionsEnum.Sales)]
public class OrderController : Controller
{
// actions...
}
Unfortunately you can not. The only possible properties that you can set are
Users and Roles. So you have to make a separate Attribute class.
I have IAuthorizationFilter filter that checks for specific roles. In case user doesn't have specified roles, I'd like to show a specific view that says something along the lines of "You don't have privileges to view this page".
I'd also like to show this view on specific url, so redirect is not an option.
Here is what I want:
1) User goes to /Admin/Payments
2) /Admin/Payments requires Admin rights
3) User is not an admin.
4) User is show page that says that he cannot access this page, yet url is /Admin/Payments
Thanks.
public class MyAuthorizeAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(System.Web.HttpContextBase httpContext)
{
// TODO: do your authorization or if you want to keep the default
// simlpy invoke the base method
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
filterContext.Result = new ViewResult
{
ViewName = "~/Views/Shared/Unauthorized.cshtml"
};
}
}
and then:
[MyAuthorize(Roles = "Admin")]
public ActionResult Payments()
{
...
}
Im using asp.net mvc built in authorize filter.
My only problem with it is that I dont want it to redirect my user to a login page when they dont have permission to perform a certain action... It always takes them to the login page even though ther are already logged on (but not with admin role).. I would like to be able to decide where to take them after they tried to perform an action ther arent allowed to..anyone?
Subclass AuthorizeAttribute and override the HandleAuthorizationFailed() method. The default logic of this method is that it sets the context's result to an HttpUnauthorizedResult, but you could do anything you want from this method. Then attribute the target method with this new attribute.
As Levi said you need to create your own custom AttributeFilter by overriding AthorizeAttribute. Something like
public class CustomAuthorizeAttribute : AuthorizeAttribute {
public string Url { get; set; }
public override void OnAuthorization(AuthorizationContext filterContext) {
if (!filterContext.HttpContext.User.Identity.IsAuthenticated) { //or custom authorization logic
filterContext.HttpContext.Response.Redirect(Url);
}
base.OnAuthorization(filterContext);
}
}
[CustomAuthorizeAttribute(Url="/Admin/AccessDenied")]
public ActionResult Admin() {
return View();
}
Taken from this similar question