Get MVC AllowAnonymous to override custom authorize attribute - asp.net-mvc

I have created a custom authorize attribute, but I need some actions to allow anonymous access. I've tried three different approaches without success: use AllowAnonymous, update the existing attribute with additional parameters, and create a new overriding attribute. Basically it seems that the controller-level attribute always gets called before the action-level attribute.
Here's the controller:
[AuthorizePublic(Sites = AuthSites.Corporate)]
public class CorporateController : SecuredController
{
[AuthorizePublic(Sites = AuthSites.Corporate, AllowAnonymous = true)]
public ActionResult Login(string returnUrl)
{
ViewBag.ReturnUrl = returnUrl;
return View();
}
}
And the attribute:
public class AuthorizePublic : AuthorizeAttribute
{
public AuthSites Sites { get; set; }
public bool AllowAnonymous { get; set; }
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
// Logic
}
}
As a last resort I can move the login actions onto their own controller, but before I do that, am I missing something to get one of these approaches to work? I'm a bit surprised that action-level attributes aren't overriding controller-level attributes.

It is the implementation of the OnAuthorization method of AuthorizeAttribute that scans for AllowAnonymousAttribute. So, you must either not override this method or re-implement this check if you want that part to work. Since you have only provided a cut-down implementation of AuthorizeAttribute, it cannot be assumed that you are not overriding this method (and thus overriding the logic that makes the check).
Also, your example controller doesn't actually show usage of the AllowAnonymousAttribute. Instead, it sets a property named AllowAnonymous. If you expect anonymous users to reach that action method, you should decorate it with the attribute that MVC is actually scanning for.
[AuthorizePublic(Sites = AuthSites.Corporate)]
public class CorporateController : SecuredController
{
[AllowAnonymous]
public ActionResult Login(string returnUrl)
{
ViewBag.ReturnUrl = returnUrl;
return View();
}
}
Alternatively, if you need to customize the AllowAnonymous behavior in some way, you can keep using the property you have, but you have to implement the Reflection code yourself to scan for AuthorizePublic and check the AllowAnonymous property.
public class AuthorizePublic : AuthorizeAttribute
{
public AuthSites Sites { get; set; }
public bool AllowAnonymous { get; set; }
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var actionDescriptor = httpContext.Items["ActionDescriptor"] as ActionDescriptor;
if (actionDescriptor != null)
{
AuthorizePublic attribute = GetAuthorizePublicAttribute(actionDescriptor);
if (attribute.AllowAnonymous)
return true;
var sites = attribute.Sites;
// Logic
}
return true;
}
public override void OnAuthorization(AuthorizationContext filterContext)
{
// Pass the current action descriptor to the AuthorizeCore
// method on the same thread by using HttpContext.Items
filterContext.HttpContext.Items["ActionDescriptor"] = filterContext.ActionDescriptor;
base.OnAuthorization(filterContext);
}
// Gets the Attribute instance of this class from an action method or contoroller.
// An action method will override a controller.
private AuthorizePublic GetAuthorizePublicAttribute(ActionDescriptor actionDescriptor)
{
AuthorizePublic result = null;
// Check if the attribute exists on the action method
result = (AuthorizePublic)actionDescriptor
.GetCustomAttributes(attributeType: typeof(AuthorizePublic), inherit: true)
.SingleOrDefault();
if (result != null)
{
return result;
}
// Check if the attribute exists on the controller
result = (AuthorizePublic)actionDescriptor
.ControllerDescriptor
.GetCustomAttributes(attributeType: typeof(AuthorizePublic), inherit: true)
.SingleOrDefault();
return result;
}
}
AuthorizeAttribute implements both Attribute and IAuthorizationFilter. With that in mind, the IAuthorizationFilter part of AuthorizeAttribute is a different runtime instance of the class than the Attribute part. So the former must use Reflection to read the property of the latter in order for it to work. You can't just read the AllowAnonymous property from the current instance and expect it to work, because you are setting the value in the attribute and the code is executing in the filter.
MVC and Web API are completely separate frameworks with their own separate configuration even though they can co-exist in the same project. MVC will completely ignore any controllers or attributes defined in Web API and vise versa.

Related

MVC Custom Authorize Attribute to validate the current user in current context

I'm use to custom authorize attribute like
public class AdminAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
return (base.AuthorizeCore(httpContext) && User.IsCurrentUserAdmin());
}
}
how to check is action call current user or not
as an example:
[OnlyYouself]
public ActionResult ViewUser(int userId)
{
...
}
means userId = current user
else redirect to previous view
You might want to build a custom attribute that looks like this:
public class AllowCurrentUserAttribute: AuthorizeAttribute
{
public string Field { get; set; }
public override void OnAuthorization(AuthorizationContext filterContext)
{
return (base.AuthorizeCore(httpContext) && filterContext.HttpContext.User.Identity.Name == filterContext.HttpContext.Request.QueryString[Field];
}
And then use it like this:
[AllowCurrentUser(Field = "userId")]
public ActionResult ViewUser(int userId)
{
...
}
There are probably better ways to check the request properties, though. Also, you may want to have a default value of "id" for the field, assuming you use the default MVC routing. If your id field is called something else, you'll want to change it.
actionContext.RequestContext.Principal.Identity

Implementing 'ReAuthentication' attribute in ASP.NET MVC 4?

Implementing a basic authorization and authentication layer is quite easy with ASP.NET MVC 4; it's all automatically generated with the 'ASP.NET MVC 4 Web Application'-project template.
However, I'm tasked with implementing some controller actions that require re-authentication and I'm aiming for a maintainable solution. Simply put in a user story, I'm trying to implement the following:
User logs on;
User navigates to a controller (attributed with [Authorize]) action which renders a form view;
User performs a POST by submitting the form;
An authentication form appears in which the user needs to re-authenticate using his/her username and password;
If authentication is succesfull, proceed with handling the POST-request.
Note that 'reauthentication' does not have to alter the state of the current user session.
Obviously, there are many ways to implementing this, but I feel like an implementation which looks similiar to the following (pseudo) sample would suit my needs.
[Authorize]
[InitializeSimpleMembership]
public class SpecialActionController : Controller
{
public ActionResult SpecialForm() { return View(); }
public ActionResult Succes() { return View(); }
[HttpPost]
[ReAuthenticate] /* <- Prompts user with reauthentication form before proceeding. */
public ActionResult SpecialForm(SpecialFormModel model)
{
if (ModelState.IsValid)
RedirectToAction("Succes");
else
return View(model);
}
}
Any suggestions?
Edit: I forgot to mention that any OAuth-related features are out of scope. External authentication is not an issue here and does not require support. In fact, with the current project I'm working on, all OAuth-related features are either removed or deactivated.
You should be able to do this using a combination of a custom AuthorizeAttribute and the Session. Override the AuthorizeCore method and let all the default authentication take place but introduce your own extra check (for re-authentication) e.g.
public class RecurringAuthorizeAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var reauth = (bool?)httpContext.Session["ReAuthenticated"];
var result = base.AuthorizeCore(httpContext) && (reauth ?? false);
httpContext.Session["ReAuthenticated"] = !result;
return result;
}
}
This should re-direct the user to the login page everytime they hit the action and they haven't re-authenticated. If the user has re-authenticated, we clear the session variable to force a login on the next request.
For this to work correctly, we need a hook to set the ReAuthentication session variable - I think the LogOn method in the AccountController would be the ideal place for this
public class AccountController : Controller
{
...
[HttpPost]
public ActionResult LogOn(LogOnModel model, string returnUrl)
{
if (ModelState.IsValid && WebSecurity.Login(model.UserName, model.Password, persistCookie: model.RememberMe))
{
Session["ReAuthenticated"] = User.Identity.IsAuthenticated;
return RedirectToLocal(returnUrl);
}
...
}
}
Then all that's left to do is decorate our controller actions
[Authorize]
public ActionResult SomePrivateAction()
{
...
}
[RecurringAuthorize]
public ActionResult SomeSuperSecretAction()
{
...
}
You should find authorization will work as normal for any actions using the default AuthorizeAttribute and any actions decorated with the RecurringAuthorizeAttribute will be forced to login everytime they request the page, which includes page refreshes.
I tried to implement the hypothetical [ReAuthenticate]-attribute, but found myself relying on reflection too much. After putting some thought into a more manageable solution, I finally came up with the following:
ReAuth class
public sealed class ReAuth
{
#region Constructor
private ReAuth(Func<System.Web.Mvc.ActionResult> onSuccessAction)
{
this.onSuccessAction = onSuccessAction;
}
#endregion
#region Public static members
public static ReAuth CreateFor(HttpSessionStateBase httpSession, Func<System.Web.Mvc.ActionResult> onSuccessAction)
{
httpSession[sessionKey] = new ReAuth(onSuccessAction);
return GetFor(httpSession);
}
public static ReAuth GetFor(HttpSessionStateBase httpSession)
{
return httpSession[sessionKey] as ReAuth;
}
public static bool ExistsFor(HttpSessionStateBase httpSession)
{
return httpSession[sessionKey] as ReAuth != null;
}
#endregion
#region Public instance members
public bool ReAuthenticated { get; set; }
public System.Web.Mvc.ActionResult Handle()
{
if (ReAuthenticated)
return onSuccessAction();
else
return new System.Web.Mvc.RedirectToRouteResult(
new System.Web.Routing.RouteValueDictionary
{
{ "Controller", "#" }, /* Replace '#' with the name of the controller that implements the re-authentication form... */
{ "Action", "#" } /* Replace '#' with the name of the action on the aforementioned controller. */
});
}
#endregion
#region Private members
private const string sessionKey = "reAuthenticationSessionKey";
private readonly Func<System.Web.Mvc.ActionResult> onSuccessAction;
#endregion
}
Implementation
Suppose we have a hypothetical controller where the solution is applied:
public class AccountInfoController : System.Web.Mvc.Controller
{
/* snip... */
[HttpPost]
public ActionResult EditAccountInfo(AccountInfo model)
{
if (ModelState.IsValid)
return ReAuth.CreateFor(Session, () => { return Success(); }).Handle();
else
return View(model);
}
}
...and, we need a controller (essentially, a 'dumb' copy of the real AccountController that does not tamper with the Forms Authentication User Session state) in which the re-authentication takes place.:
public class ReAuthController : System.Web.Mvc.Controller
{
/* Snip... */
[HttpPost]
public ActionResult LogOn(LogOnModel model)
{
if (ModelState.IsValid)
{
ReAuth.GetFor(Session).ReAuthenticated = Membership.ValidateUser(model.User, model.Password);
return ReAuth.Handle();
}
return View(model);
}
}
As far as I know, this is a manageable solution. It does rely a lot on storing objects into session state. (Especially the object state of the controller which implements the ReAuth-class) If anyone has additional suggestions, please let me know!

A way to exclude action filters in ASP.NET MVC?

I've run into several cases in ASP.NET MVC where I wanted to apply an action filter on every action except one or two. For example, say you have an AccountController. Every action in it requires the user be logged in, so you add [Authorize] at the controller level. But say you want to include the login page in AccountController. The problem is, users sent to the login page aren't authorized, so this would result in an infinite loop.
The obvious fix (other than moving the Login action to another controller) is to move the [Authorize] from the controller to all action methods except Login. Well that ain't fun, especially when you have a lot of methods or forget to add [Authorize] to a new method.
Rails makes this easy with an ability to exclude filters. ASP.NET MVC doesn't let you. So I decided to make it possible and it was easier than I thought.
/// <summary>
/// This will disable any filters of the given type from being applied. This is useful when, say, all but on action need the Authorize filter.
/// </summary>
[AttributeUsage(AttributeTargets.Method|AttributeTargets.Class, AllowMultiple=true)]
public class ExcludeFilterAttribute : ActionFilterAttribute
{
public ExcludeFilterAttribute(Type toExclude)
{
FilterToExclude = toExclude;
}
/// <summary>
/// The type of filter that will be ignored.
/// </summary>
public Type FilterToExclude
{
get;
private set;
}
}
/// <summary>
/// A subclass of ControllerActionInvoker that implements the functionality of IgnoreFilterAttribute. To use this, just override Controller.CreateActionInvoker() and return an instance of this.
/// </summary>
public class ControllerActionInvokerWithExcludeFilter : ControllerActionInvoker
{
protected override FilterInfo GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
{
//base implementation does all the hard work. we just prune off the filters to ignore
var filterInfo = base.GetFilters(controllerContext, actionDescriptor);
foreach( var toExclude in filterInfo.ActionFilters.OfType<ExcludeFilterAttribute>().Select(f=>f.FilterToExclude).ToArray() )
{
RemoveWhere(filterInfo.ActionFilters, filter => toExclude.IsAssignableFrom(filter.GetType()));
RemoveWhere(filterInfo.AuthorizationFilters, filter => toExclude.IsAssignableFrom(filter.GetType()));
RemoveWhere(filterInfo.ExceptionFilters, filter => toExclude.IsAssignableFrom(filter.GetType()));
RemoveWhere(filterInfo.ResultFilters, filter => toExclude.IsAssignableFrom(filter.GetType()));
}
return filterInfo;
}
/// <summary>
/// Removes all elements from the list that satisfy the condition. Returns the list that was passed in (minus removed elements) for chaining. Ripped from one of my helper libraries (where it was a pretty extension method).
/// </summary>
private static IList<T> RemoveWhere<T>(IList<T> list, Predicate<T> predicate)
{
if (list == null || list.Count == 0)
return list;
//note: didn't use foreach because an exception will be thrown when you remove items during enumeration
for (var i = 0; i < list.Count; i++)
{
var item = list[i];
if (predicate(item))
{
list.RemoveAt(i);
i--;
}
}
return list;
}
}
/// <summary>
/// An example of using the ExcludeFilterAttribute. In this case, Action1 and Action3 require authorization but not Action2. Notice the CreateActionInvoker() override. That's necessary for the attribute to work and is probably best to put in some base class.
/// </summary>
[Authorize]
public class ExampleController : Controller
{
protected override IActionInvoker CreateActionInvoker()
{
return new ControllerActionInvokerWithExcludeFilter();
}
public ActionResult Action1()
{
return View();
}
[ExcludeFilter(typeof(AuthorizeAttribute))]
public ActionResult Action2()
{
return View();
}
public ActionResult Action3()
{
return View();
}
}
The example is right there. As you can see, this was pretty straightforward to do and works great. I hope it's useful to anyone?
I prefer the solution outlined here. Though it's not as generic a solution as yours, I found it a bit more straightforward.
In my case, I was looking for a way to enable a CompressionFilter on everything but a few items. So I created an empty attribute like this:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public sealed class DisableCompression : Attribute { }
Then in the main attribute, check for the presence of the attribute like so:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
public class CompressionFilter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
bool disabled = filterContext.ActionDescriptor.IsDefined(typeof(DisableCompression), true) ||
filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(DisableCompression), true);
if (disabled)
return;
// action filter logic here...
}
}
Though the page I linked to mentions that this is for MVC 3, it seems to work well enough way back in MVC 1 as well.
EDIT: showing some usage here in response to comments. Before I made the changes above, it looked exactly like this, except without the [DisableCompression] attribute flagging the method I wanted to exclude. There's no other refactoring involved.
[CompressionFilter]
public abstract class BaseController : Controller
{
}
public class SomeController : BaseController
{
public ActionResult WantThisActionCompressed()
{
// code
}
[DisableCompression]
public ActionResult DontWantThisActionCompressed()
{
// code
}
}
I assume for years ago that the [AllowAnnonymous] attribute hadn't been added to ASP.NET MVC. Today I can have the [Authorize] attribute on top of my controller applying to all the Action methods and I just simply override this in Actions I require unauthorized users by adding the [AllowAnonymous] attributes to the specific actions.

ASP.NET MVC: Ignore custom attribute in a base controller class

I have a number of Controllers in my project that all inherit from a controller I've named BaseController. I wrote a custom attribute that I applied to the entire BaseController class, so that each time an action runs in any of my controllers, that attribute will run first.
The problem is that I have a couple of controller actions that I'd like to ignore that attribute, but I don't know how to do it.
Can anyone help? I'm using MVC 1.
Thanks.
In your custom attribute, you can add this ShouldRun() check like this:
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (ShouldRun(filterContext))
{
// proceed with your code
}
}
private bool ShouldRun(ActionExecutingContext filterContext)
{
var ignoreAttributes = filterContext.ActionDescriptor.GetCustomAttributes(typeof(IgnoreMyCustomAttribute), false);
if (ignoreAttributes.Length > 0)
return false;
return true;
}
ShouldRun() simply checks whether there's a "IgnoreMyCustomAttribute" on your action. If it's there, then your custom attribute won't do anything.
You'll now want to create a simple IgnoreMyCustomAttribute, which doesn't do anything:
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class IgnoreMyCustomAttribute: ActionFilterAttribute
{
}
Whenever you decorate your controller action with [IgnoreMyCustom], then MyCustomAttribute won't do anything. e.g.:
[IgnoreMyCustom]
public ViewResult MyAction() {
}
I had a similar need for something like this and found that by creating an authorization filter (implementing/deriving from FilterAttribute, IAuthorizationFilter) rather than a regular action filter (deriving from ActionFilterAttribute), and setting Inherited=true and AllowMultiple=false on the attribute, that it would only run once at the appropriate spot.
This means I am able to "cascade" my filter down from a base controller (the site-wide default), to a derived controller (for example the AdminController or whatever), or even further down to an individual action method.
For example,
[AttributeUsage(AttributeTargets.Class|AttributeTargets.Method, Inherited=true, AllowMultiple=false)]
public class MyCustomAttribute : FilterAttribute, IAuthorizationFilter
{
private MyCustomMode _Mode;
public MyCustomAttribute(MyCustomMode mode)
{
_Mode = mode;
}
public virtual void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext == null)
{
throw new ArgumentNullException("filterContext");
}
// run my own logic here.
// set the filterContext.Result to anything non-null (such as
// a RedirectResult?) to skip the action method's execution.
//
//
}
}
public enum MyCustomMode
{
Enforce,
Ignore
}
And then to use it, I can apply it to my super-controller,
[MyCustomAttribute(Ignore)]
public class BaseController : Controller
{
}
And I can change/override it for specific controllers, or even for specific actions!
[MyCustomAttribute(Enforce)]
public class AdministrationController : BaseController
{
public ActionResult Index()
{
}
[MyCustomAttribute(Ignore)]
public ActionResult SomeBasicPageSuchAsAHelpDocument()
{
}
}
This allowed me to "turn off" the filter for specific cases, while still being able to apply it as a default on either the whole controller or whole application.
Good luck!
I'm not sure there is an easy way to remove attributes in this situation. But I have done something similar for a project and what I did, as it was only in a few instances I didn't want my attribute to run, was to create two attributes.
My first attribute was applied to my base controller as you've done but it was aware of the existance of a second attribute and by implementing that second attribute I could disable the attribute on the base class from running.
Not sure if it was the best solution but it worked for me.
This was applied to the base controller:
/// <summary>
/// This is used to force the schema to HTTP is it is HTTPS.
/// RequireHttpsAttribute or OptionalHttpsAttribute takes precedence if used.
/// </summary>
public class RequireHttpAttribute : FilterAttribute, IAuthorizationFilter
{
public virtual void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext == null)
throw new ArgumentNullException("filterContext");
if (filterContext.HttpContext.Request.IsSecureConnection)
{
object[] attributes = filterContext.ActionDescriptor.GetCustomAttributes(true);
if (!attributes.Any(a => a is RequireHttpsAttribute || a is OptionalHttpsAttribute))
{
HandleHttpsRequest(filterContext);
}
}
}
protected virtual void HandleHttpsRequest(AuthorizationContext filterContext)
{
// only redirect for GET method, otherwise browser may not propogate the verb and request body correctly
if (!string.Equals(filterContext.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
throw new InvalidOperationException(MvcResources.RequireHttpAttribute_MustNotUseSsl);
// redirect to HTTP version
string url = "http://" + filterContext.HttpContext.Request.Url.Host + filterContext.HttpContext.Request.RawUrl;
filterContext.Result = new RedirectResult(url);
}
}
Like so:
[RequireHttp]
public abstract class Controller : System.Web.Mvc.Controller
{
}
I could then use what is effectively a dummy attribute to disable it.
/// <summary>
/// This attribute allows the action to be server on HTTP and HTTPS but neither is enforce.
/// RequireHttpsAttribute takes precedence if used.
/// </summary>
public class OptionalHttpsAttribute : FilterAttribute
{
// This is deliberately empty, the attribute is used by RequireHttpAttribute to stop it changing schema to HTTP
}
Like so:
[OptionalHttps]
public ActionResult OptionalHttps()
{
return View();
}

ASP .NET MVC Securing a Controller/Action

If I want only administrator to access the action called "ManagerUser", I know I can do this:
[Authorize( Roles = Constants.ROLES_ADMINISTRATOR )]
public ActionResult ManageUser( string id )
{
}
What if I want to give everyone access except to administrator? I do not want to write all roles up there on function :|.
Any recommendations/way outs?
You can create your own custom Authorize attribute, something like "AuthorizeAllExceptAdmin." Within that class you would simply need to check whether or not the current user was an admin, and if they were reject it, otherwise accept it.
Here's a good tutorial, but you'll probably end up with something like:
public class AuthorizeAllExceptAdmin : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
return !httpContext.User.IsInRole(Constants.ROLES_ADMINISTRATOR);
}
}
Then your controller method becomes:
[AuthorizeAllExceptAdmin]
public ActionResult SomethingOnlyNonAdminsCanDo()
{
}
Here's an example of the custom attribute that takes in roles to deny.
public class DoNotAuthorize : AuthorizeAttribute
{
private IEnumerable<string> _rolesToReject;
public DoNotAuthorize(IEnumerable<string> rolesToReject)
{
_rolesToReject = rolesToReject;
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
foreach (var role in _rolesToReject)
{
if (httpContext.User.IsInRole(role))
return false;
}
return true;
}
}
Then your controller method becomes:
[DoNotAuthorize(new [] {Constants.ROLES_ADMINISTRATOR})]
public ActionResult SomethingOnlyNonAdminsCanDo()
{
}
I would put some thought into it before choosing one of the above options. If you think you'll have several methods (or entire controllers) with similar authorization requirements (i.e, several actions an admin can not perform) then I would stick with the non-parameterized custom attribute. This way, you can evolve them all together (by only changing the custom attribute) later on. For example, maybe later on you want admins to be able to go into a special mode where they can perform these actions.
Alternatively, if the autorization is more varied amongst the actions, then using the parameterized list makes sense, since they'll evolve relatively independently.
Besides creating a custom AuthorizeAttribute, suggested by manu, you could use PrincipalPermission, with a Deny-SecurityAction:
[PrincipalPermission(SecurityAction.Deny, Role="Administrator")]
In my app I don't use roles so I have to query the database to determine whether the user has access or not. The benefits of the code below is that you can redirect the user to a certain action very easily. I explained the code in my blog post at http://blog.athe.la/2009/12/implementing-permission-via-windows-authentication-in-asp-mvc-using-action-filters/
public class DatabaseRepository()
{
private readonly DatabaseDataContext db = new DatabaseDataContext();
public bool UserHasPermission(string userLogon) {
return (from permission this.db.Permissions
where permission.HasPermissionSw == true
select permission).Contains(userLogon);
}
}
public class UserHasPermission: ActionFilterAttribute
{
private readonly DatabaseRepository databaseRepository = new DatabaseRepository();
private readonly string redirectAction;
public UserHasPermission(string redirectTo)
{
this.redirectAction = redirectTo;
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
string userLogon = filterContext.HttpContext.User.Identity.Name;
if (!this.databaseRepository.UserHasPermission(userLogon))
{
string routeController = filterContext.Controller.ControllerContext.RouteData.Values["controller"];
filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new { controller = routeController, action = this.redirectAction }));
}
}
}
Your controller would then look something like this:
[UserHasPermission("NoAccess")]
public ActionResult SecretArea()
{
// run all the logic
return View();
}
public ActionResult NoAccess()
{
return View();
}

Resources