Help with asp.net mvc authorization - asp.net-mvc

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

Related

MvcSitemapProvider throwing Overflow exception when using currentNode

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.

Changing the view in an ASP.NET MVC Filter

I want to redirect the user to a different view if they are using a mobile browser. I've decided I'd like to do this using MVC filters by applying it to actions which I want to have a mobile view.
I believe this redirect needs to happen in OnActionExecuted, however the filterContext does not contain information on the view - it does, however in OnResultExecuted, but by this time I believe it is too late to change the view.
How can I intercept the view name and change the ViewResult?
This is what I have in the result executed and what I'd like to have work in Action Executed.
public class MobilePageFilter : ActionFilterAttribute
{
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
if(filterContext.Result is ViewResult)
{
if (isMobileSite(filterContext.HttpContext.Session[SetMobile.SESSION_USE_MOBILE]))
{
ViewResult viewResult = (ViewResult)filterContext.Result;
string viewName = viewResult.ViewName;
filterContext.Result = new ViewResult
{
ViewName = "Mobile/" + viewName,
ViewData = viewResult.ViewData,
TempData = viewResult.TempData
};
}
}
base.OnResultExecuted(filterContext);
}
}
I would recommend you the following blog post which explains a better alternative to achieve what you are asking for rather than using action filters.
This is what I ended up doing, and wrapped up into a reusable attribute and the great thing is it retains the original URL while redirecting (or applying whatever result you wish) based on your requirements:
public class AuthoriseSiteAccessAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
// Perform your condition, or straight result assignment here.
// For me I had to test the existance of a cookie.
if (yourConditionHere)
filterContext.Result = new SiteAccessDeniedResult();
}
}
public class SiteAccessDeniedResult : ViewResult
{
public SiteAccessDeniedResult()
{
ViewName = "~/Views/SiteAccess/Login.cshtml";
}
}
Then just add the attribute [SiteAccessAuthorise] to your controllers you wish to apply the authorisation access to (in my case) or add it to a BaseController. Make sure though the action you are redirecting to's underlying controller does not have the attribute though, or you'll be caught in an endless loop!

create the authorize filter with parameter asp.net mvc

I have to develop an authorize filter in asp.net mvc.I have got five categories of users in my site and my site uses custom created authentication system.Now i have a controller action which should be accessible to 3 out of those five type of users.How to create a filter (basically authorize) and use it which fulfills my requirement?I think i need to create the authorize filter with parameter.I should be able to use something like this.
Authorize[UsersType="admin,accountant,operator"]
technology used : Asp.net MVC
Thanks in Advance
Create an Attribute class that Inherits the AuthorizeAttribute class of MVC.
Create a constructor in your attribute class that accepts the parameter UsersType
Override the appropriate methods of AuthorizeAttribute that is needed.
Parse the parameter in your appropriate override method.
public class AuthorizeUserAttribute :AuthorizeAttribute
{
private string[] _userType { get; set; }
public AuthorizeUserAttribute(string UsersType)
{
// parse your usertypes here.
}
protected override void OnAuthorization(AuthorizationContext filterContext)
{
// do the appropriate assigning and authorizing of methods here
....
base.OnAuthorization(filterContext);
}
}
Now you can put an attribute in your Method in your controller
[AuthorizeUser("admin,accountant,operator")]
public ActionMethod Index()
{
return View();
}

ASP.NET MVC - Dynamic Authorization

I am building a simple CMS in which roles are set dynamically in the admin panel. The existing way of authorizing a controller method, adding [Authorize(Roles="admin")] for example, is therefore no longer sufficient. The role-action relationship must be stored in the database, so that end users can easily give/take permissions to/from others in the admin panel. How can I implement this?
If you want to take control of the authorization process, you should subclass AuthorizeAttribute and override the AuthorizeCore method. Then simply decorate your controllers with your CmsAuthorizeAttribute instead of the default.
public class CmsAuthorizeAttribute : AuthorizeAttribute
{
public override virtual bool AuthorizeCore(HttpContextBase httpContext)
{
IPrincipal user = httpContext.User;
IIdentity identity = user.Identity;
if (!identity.IsAuthenticated) {
return false;
}
bool isAuthorized = true;
// TODO: perform custom authorization against the CMS
return isAuthorized;
}
}
The downside to this is that you won't have access to ctor-injected IoC, so you'll have to request any dependencies from the container directly.
That is exactly what the ASP.NET membership / profile stuff does for you. And it works with the Authorize attribute.
If you want to roll your own you could create a custom action filter that mimics the behavior of the standard Authorize action filter does. Pseudo code below.
public MyAuthorizeAttribute : ActionFilterAttribute
{
public string MyRole { get; set; }
public void OnActionExecuting(ControllerContext context)
{
if (!(bool)Session["userIsAuthenticated"])
{
throw new AuthenticationException("Must log in.");
}
if (!Session["userRoles"].Contains(MyRole))
{
throw new AuthenticationException("Must have role " + MyRole);
}
}
}
The role - action relationship must be
stored in the database
You will have to check your security within the controller method, unless you want to subclass AuthorizeAttribute so that it looks up the roles from the database for you.

Setting result for IAuthorizationFilter

I am looking to set the result action from a failed IAuthorizationFilter. However I am unsure how to create an ActionResult from inside the Filter. The controller doesn't seem to be accible from inside the filter so my usual View("SomeView") isn't working. Is there a way to get the controler or else another way of creating an actionresult as it doesn't appear to be instantiable?
Doesn't work:
[AttributeUsage(AttributeTargets.Method)]
public sealed class RequiresAuthenticationAttribute : ActionFilterAttribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationContext context)
{
if (!context.HttpContext.User.Identity.IsAuthenticated)
{
context.Result = View("User/Login");
}
}
}
You should look at the implementation of IAuthorizationFilter that comes with the MVC framework, AuthorizeAttribute. If you are using forms authentication, there's no need for you to set the result to User/Login. You can raise a 401 HTTP status response and ASP.NET Will redirect to the login page for you.
The one issue with setting the result to user/login is that the user's address bar is not updated, so they will be on the login page, but the URL won't match. For some people, this is not an issue. But some people want their site's URL to correspond to what the user sees in their browser.
You can instantiate the appropriate ActionResult directly, then set it on the context. For example:
public void OnAuthorization(AuthorizationContext context)
{
if (!context.HttpContext.User.Identity.IsAuthenticated)
{
context.Result = new ViewResult { ViewName = "Whatever" };
}
}

Resources