Impersonate for one request (Asp.net MVC) - asp.net-mvc

In my ASP.net MVC project I've got (among other roles) moderators and users. I want to give the moderators the option to "see current page as user".
My approach is to create a ActionFilterAttribute and overload OnActionExecuting & OnResultExecuted as the page is then rendered for the given user.
The first idea there was to juggle with the Roles:
OnActionExecuting {
... //various checks, if role exist, if user want to switch
var tempRoles = Roles.getRolesForUser(user);
filterContext.HttpContext.Items["tempRole"] = tempRoles;
Roles.RemoveUserFromRoles(user, tempRoles)
Roles.AddUserToRole(user, targetRole);
}
and then
OnResultExecuted {
//if switched view
{
Roles.RemoveUserFromRole(user,targetRole)
Roles.AddUserToRoles(filterContext.HttpContext.Items["tempRole"])
}
This works, but in a worst case scenario the roles are gone, so i prefer to not touch them...
My second idea was to create a dummy user add him to the userroles sign the moderator into this account with FormsAuthentication.SetAuthCookie(dummyUser, true) and revert everything in the OnResultExecuted, so in a worst case scenario the user is in the dummyRole (where he can logout) and the dummyUser is in the Database.
After debugging and researching I realised that SetAuthCookie requires a Redirect to come into effect - so it doesn't work this way.
The questions:
Is there a way to force SetAuthCookie to come into affect without a redirect
Any other suggestion/approaches how to accomplish this "see page as other user"?
If my first idea is the only solution, how do i make it foolproof?

Ahoi Christian,
you could decorate the class SqlRoleProvider and add it to the role manager.
See Sample Role-Provider Implementation:
http://msdn.microsoft.com/en-us/library/tksy7hd7%28v=vs.100%29.aspx
The decorated SqlRoleProvider could overwrite the IsUserInRole method and thereby implement impersonation functionality.
edit: I have added the code below:
public class MyRoleProvider : SqlRoleProvider
{
private static ConcurrentDictionary<string, string> impersonationList;
public MyRoleProvider() : base()
{
impersonationList = new ConcurrentDictionary<string, string>();
}
public static void startImpersonate(string username, string rolename)
{
impersonationList.TryAdd(username,rolename);
}
public override string[] GetRolesForUser(string username) {
if (impersonationList.ContainsKey(username))
return new string[] { impersonationList[username] };
else
return base.GetRolesForUser(username);
}
public static void stopImpersonate(string username)
{
string rolename;
impersonationList.TryRemove(username, out rolename);
}
}

Related

How to implement role authorization with custom database?

I have an application which requires role authorization using custom database. The database is set up with a tblUsers table that has a reference to a tblRoles table. The users are also already assigned to their roles.
I also want to use the [Authorize(Role = "RoleName")] attribute on each action to check if an authenticated user is assigned to "RoleName" in the database. I'm having a lot of trouble figuring out where I need to make a modification to the [Authorize] attribute so it behaves that way. I just want to see if a username has a role, I won't have a page to manage roles in the database.
I have tried implementing custom storage providers for ASP.NET Core Identity, but it's starting to look like this is not what I need because I'm not gonna be managing roles within the application, and I can't tell how it affects the behavior of [Authorize] attribute.
Also, it's likely that I have a false assumption in my understanding on how the [Authorize] attribute even works. If you notice it, I would appreciate if you could point it out.
I had a similar problem when my client asked for granular permissions for each role. I couldn't find a way to modify the Authorize attribute but was able to implement the solution with a custom attribute. But it depends on one thing i.e can you get the userId of the calling user? I used cookie authentication so I just include the userId in my claims when someone logs in so when a request comes I can always get it from there. I think the built-in Session logic in asp.net might get the job done too, I can't say for sure though. Anyways the logic for custom authorization goes like this:
Load users and roles from database to cache on startup. If you haven't set up a cache in your program (and don't want to) you can simply make your own for this purpose by making a UserRoleCache class with 2 static lists in it. Also there are several ways of loading data from db on startup but I found it easy to do that directly in Program.cs as you'll see below.
Define your custom attribute to check if the calling user has the required role by iterating over lists in cache and return 403 if not.
Modify your Program class like:
public class Program
{
public static async Task Main(string[] args)
{
IWebHost webHost = CreateWebHostBuilder(args).Build();
using (var scope = webHost.Services.CreateScope())
{
//Get the DbContext instance. Replace MyDbContext with the
//actual name of the context in your program
var context = scope.ServiceProvider.GetRequiredService<MyDbContext>();
List<User> users = await context.User.ToListAsync();
List<Role> roles = await context.Role.ToListAsync();
//You may make getters and setters, this is just to give you an idea
UserRoleCache.users = users;
UserRoleCache.roles = roles;
}
webHost.Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>();
}
Then comes the logic for checking if user has a role. Notice I've used an array of roles because sometimes you'll want to allow access to multiple roles.
public class RoleRequirementFilter : IAuthorizationFilter
{
private readonly string[] _roles;
public PermissionRequirementFilter(string[] roles)
{
_roles = roles;
}
public void OnAuthorization(AuthorizationFilterContext context)
{
bool hasRole = false;
//Assuming there's a way you can get the userId
var userId = GetUserId();
User user = UserRoleCache.users.FirstOrDefault(x => x.Id == userId);
//Where roleType is the name of the role like Admin, Manager etc
List<Role> roles = UserRoleCache.roles.FindAll(x => _roles.Contains(x.RoleType))
foreach(var role in roles)
{
if(user.RoleId == role.Id)
{
hasRole = true;
break;
}
}
if (!hasRole)
context.Result = new StatusCodeResult(403);
}
}
Finally make the Role attribute
public class RoleAttribute : TypeFilterAttribute
{
public RoleAttribute(params string[] roles) : base(typeof(RoleRequirementFilter))
{
Arguments = new object[] { roles };
}
}
Now you can use the Role attribute in your controllers:
public class SampleController : ControllerBase
{
[HttpGet]
[Role("Admin", "Manager")]
public async Task<ActionResult> Get()
{
}
[HttpPost]
[Role("Admin")]
public async Task<ActionResult> Post()
{
}
}

Authentification and Authorization in ASP.NET MVC 5

I am very confused with Authentication and Authorization in ASP.NET MVC 5.
I am working on an existing website and I need to add security in it. By security I mean Authentication (Logins) and Authorization (Roles). I have access to a Webservice, but not directly to the database though I can access the Entities (Users, Roles etc.).
Membership Provider seems to be a bit old, so I took a look at Identity but it looks complicated to implement to an existing project, especially when I don't have direct access to the database.
What would be a good solution ? What are the best practices ?
Could you suggest me any good resource so I can suits my needs ?
Thank you.
In case someone feel as lost as I was, here is a potential solution using Claims. Ath the end, you will know how to handle Authentication, Authorization and Roles.
Hope this can help.
Startup config
In the root folder off my project I have created a file, startup.cs. She contains a partial class that we will use to configure the application to use a cookie that store the signed user.
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
}
}
Then, in the App_Start I have a file, Startup.Auth.cs
public partial class Startup
{
public void ConfigureAuth(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login")
});
}
}
Controller
First, I have created an AcountController.cs with attribute of type IAuthenticationManager. This attribute gets the authentication middleware functionality available on the current request.
public class CompteController : Controller
{
private IAuthenticationManager AuthenticationManager
{
get
{
return HttpContext.GetOwinContext().Authentication;
}
}
}
Then, I have a classic view called Login with GET and POST. In the post I check in my Webservice if the user can Log In. If he can, I call a the magic function to authenticate. In this code, the class User is the custom User I get in the Webservice. He don't implement IUser.
private void AuthentifyUser(User user, bool isPersistent)
{
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
CustomIdentity identity = new CustomIdentity(user);
CustomPrincipal principal = new CustomPrincipal(identity);
Thread.CurrentPrincipal = principal;
AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
}
Last important method in my Controller allow users to Log Out.
public ActionResult Deconnexion()
{
AuthenticationManager.SignOut();
return RedirectToAction("Login", "Account");
}
Claims
CustomIdentity and CustomPrincipal are two custom class that I use for the Claims system. They indirectly implement IIdentity and IPrincipal. I put them in a separate new folder.
-Remember, A principal object represents the security context of the user on whose behalf the code is running, including that user's identity (IIdentity) and any roles to which they belong.
-An identity object represents the user on whose behalf the code is running.
public class HosteamIdentity : ClaimsIdentity
{
public HosteamIdentity(User user)
: base(DefaultAuthenticationTypes.ApplicationCookie)
{
AddClaim(new Claim("IdUser", user.Id.ToString()));
AddClaim(new Claim(ClaimTypes.Name, user.Name));
AddClaim(new Claim(ClaimTypes.Role, user.Role));
}
public int IdUser
{
get
{
return Convert.ToInt32(FindFirst("IdUser").Value);
}
}
//Other Getters to facilitate acces to the Claims.
}
The Principal gives us access to the Identity.
public class HosteamPrincipal : ClaimsPrincipal
{
private readonly HosteamIdentity _identity;
public new HosteamIdentity Identity
{
get { return _identity; }
}
public HosteamPrincipal(HosteamIdentity identity)
{
_identity = identity;
}
public override bool IsInRole(string role)
{
return _identity.Role == role;
}
}
Access the CustomPrincipal
Now, I will lgo to the gGlobal.asax, here we will override the Application_PostAuthenticateRequest event. This event is fired when a security module has established the identity of the user.
We will use Thread.CurrentPrincipal, this static object Gets or sets the thread's current principal (for role-based security), so it is perfectly adapted to our case !
You may have to adapt the code here. I personally have to request my Webservice, this may not be your case.
Just talking briefly about our constructors. The fist is empty, we will use it when we don't care about Roles
protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{
if (HttpContext.Current.User.Identity.IsAuthenticated)
{
Thread.CurrentPrincipal = new HosteamPrincipal(
new HosteamIdentity(
WebService.GetUser(
HttpContext.Current.User.Identity.Name)));
}
}
In most case, retrieving the user by is Name is not a good practice. Please, adapt the above code to your solution.
Authorize Attribute Filter
Now, it will be great if we could easily tell which Controller or Action can be accessed by an authenticated user. To do so, we will use Filters.
Filters are custom classes that provide both a declarative and programmatic means to add pre-action and post-action behavior to controller action methods. We use them as annotation, for example [Authorize] is a Filter.
As there is to many things to explain, I will let you read the comments, they are very explicit.
Just talking briefly about our Constructors.
-The first one is empty, we will use it when we don't care about Roles. We access it by writing the annotation [CustomAuthorize] abose a Controller or an Action.
-The second one, takes an array of Roles, we will use it by writing the annotation [CustomAuthorize("Role1", "Role2", etc.)] abose a Controller or an Action. He will define which Roles access the Controller or action
public class CustomAuthorize : AuthorizeAttribute
{
private new string[] Roles { get; set; }
public CustomAuthorize() { }
public CustomAuthorize(params string[] roles)
{
this.Roles = roles[0].Split(',');
}
/// <summary>
/// Check for Authorizations (Authenticated, Roles etc.)
/// </summary>
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (httpContext.Request.IsAuthenticated)
if (Roles != null)
{
foreach (string role in Roles)
if (((HosteamPrincipal)Thread.CurrentPrincipal).IsInRole(role))
return true;
return false;
}
else
return true;
return false;
}
/// <summary>
/// Defines actions to do when Authorizations are given or declined
/// </summary>
public override void OnAuthorization(AuthorizationContext filterContext)
{
if (!AuthorizeCore(filterContext.HttpContext))
HandleUnauthorizedRequest(filterContext);
}
/// <summary>
/// Manage when an Authorization is declined
/// </summary>
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
if (filterContext.HttpContext.Request.IsAuthenticated)
filterContext.Result = new HttpStatusCodeResult(HttpStatusCode.Forbidden);
else
base.HandleUnauthorizedRequest(filterContext);
}
}

How to tap into the automatic repeated login?

I am making an ASP.Net MVC3 application. I use for now the built in Authentication code that comes with a Visual Studio 2010 project. The problem is dat I need to retrieve the logged in user's database ID as soon as he has logged in. I do that now by adding code to the Login Action of the Account controller that retrieves the ID from the database by looking it up by username. This works for new logins, but not for "remembered" ones. On restarting the application the last user is automatically logged in again, but the Login code is not fired, so I do not get the database ID.
How can I solve this?
EDIT:
I tried to implement Daniel's solutions which looks promising and I came up with this code. It nevers gets called though! Where have I gone wrong?
Global.asax.cs:
protected void Application_Start()
{
Database.SetInitializer<StandInContext>(new StandInInitializer());
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
this.AuthenticateRequest +=
new EventHandler(MvcApplication_AuthenticateRequest);
}
void MvcApplication_AuthenticateRequest(object sender, EventArgs e)
{
if(Request.IsAuthenticated)
{
using (var db = new StandInContext())
{
var authenticatedUser = db.AuthenticatedUsers.SingleOrDefault(
user => user.Username == User.Identity.Name);
if (authenticatedUser == null)
return;
var person = db.Persons.Find(authenticatedUser.PersonID);
if (person == null)
return;
Context.User = new CustomPrincipal(
User.Identity, new string[] { "user" })
{
Fullname = person.FullName,
PersonID = person.PersonID,
};
}
}
}
You can use the AuthenticateRequest event in your Global.asax.cs:
protected void Application_AuthenticateRequest()
{
if (Request.IsAuthenticated)
{
// retrieve user from repository
var user = _membershipService.GetUserByName(User.Identity.Name);
// do other stuff
}
}
Update:
Now that I see what you're trying to do a little clearer, I would recommend against using sessions in this particular case. One reason is that Session requires a reference to System.Web, which you don't have access to from some places, like a business logic layer in a separate class library. IPrincipal, on the other hand, exists for this very reason.
If you need to store more user information than what IPrincioal provides, you simply implement it and add your own properties to it. Easier yet, you can just derive from GenericPrincipal, which implements IPrincipal and adds some basic role checking functionality:
CustomPrincipal.cs
public class CustomPrincipal : GenericPrincipal
{
public CustomPrincipal(IIdentity identity, string[] roles)
: base(identity, roles) { }
public Guid Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
...
}
So then you replace the default principal with your own in AuthenticateRequest, as before:
Global.asax.cs
protected void Application_AuthenticateRequest()
{
if (Request.IsAuthenticated)
Context.User = _securityService.GetCustomPrincipal(User.Identity.Name);
}
And that is it. The greatest advantage you get is that you automatically get access to your user data from literally everywhere, without having to stick a userId parameter into all your methods. All you need to do is cast the current principal back to CustomPrincipal, and access your data like so:
From your razor views:
<p>Hello, #((CustomPrincipal)User).FirstName!</p>
From your controllers:
var firstName = ((CustomPrincipal)User).FirstName;
From a business logic layer in another assembly:
var firstName = ((CustomPrincipal)Thread.CurrentPrincipal).FirstName;
To keep things DRY, you could pack this into an extension method and hang it off IPrincipal, like so:
public static class PrincipalExtensions
{
public static string GetFirstName(this IPrincipal principal)
{
var customPrincipal = principal as CustomPrincipal;
return customPrincipal != null ? customPrincipal.FirstName : "";
}
}
And then you would just do #User.GetFirstName(), var userName = User.GetFirstName(), Thread.CurrentPrincipal.GetFirstName(), etc.
Hope this helps.
I wasn´t thinking clear. I was trying to store the userinfo in the Session object, while it available through the User object. Sorry to have wasted your time.

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.

ASP.Net MVC how to determine if a user can access a URL?

So I was reading another question regarding login loop when you have a user logging in, set to return to a URL which they might not have access to after logging in (ie. an admin page, and the user logs in with a normal account).
The solution under WebForms seems to be to utilize the UrlAuthorizationModule.CheckUrlAccessForPrincipal method. However that does not work for URLs going to Action Methods secured with the Authorize Attribute. I figured I could work out which method the URL was pointing at and reflect over it to solve my problem - but I can't seem to work out how I get this information out of the routing table.
Anyone ever worked with this, or have a solution for this? If I can just get hold of the route information from a URL I think I could work the rest out, but if anyone has a generic solution - ie. some hidden method akin to the before mentioned one for MVC, then that would be totally awesome as well.
I'm not asking how to check if the User has acces to a specified Controller/Action pair. I first and foremost need to work out how to get the Controller/Action pair from the RouteTable based off the URL. The reason for all the background story, is in case that there does indeed exist an equivalent to UrlAuthorizationModule.CheckUrlAccessForPrincipal for MVC.
John Farrell (jfar)'s answer (SecurityTrimmingExtensions class) updated for MVC 4:
public static class SecurityCheck
{
public static bool ActionIsAuthorized(string actionName, string controllerName)
{
IControllerFactory factory = ControllerBuilder.Current.GetControllerFactory();
ControllerBase controller = factory.CreateController(HttpContext.Current.Request.RequestContext, controllerName) as ControllerBase;
var controllerContext = new ControllerContext(HttpContext.Current.Request.RequestContext, controller);
var controllerDescriptor = new ReflectedControllerDescriptor(controller.GetType());
var actionDescriptor = controllerDescriptor.FindAction(controllerContext, actionName);
AuthorizationContext authContext = new AuthorizationContext(controllerContext, actionDescriptor);
foreach (var authAttribute in actionDescriptor.GetFilterAttributes(true).Where(a => a is AuthorizeAttribute).Select(a => a as AuthorizeAttribute))
{
authAttribute.OnAuthorization(authContext);
if (authContext.Result != null)
return false;
}
return true;
}
}
I ported and hacked this code from the MvcSitemap:
public static class SecurityTrimmingExtensions
{
/// <summary>
/// Returns true if a specific controller action exists and
/// the user has the ability to access it.
/// </summary>
/// <param name="htmlHelper"></param>
/// <param name="actionName"></param>
/// <param name="controllerName"></param>
/// <returns></returns>
public static bool HasActionPermission( this HtmlHelper htmlHelper, string actionName, string controllerName )
{
//if the controller name is empty the ASP.NET convention is:
//"we are linking to a different controller
ControllerBase controllerToLinkTo = string.IsNullOrEmpty(controllerName)
? htmlHelper.ViewContext.Controller
: GetControllerByName(htmlHelper, controllerName);
var controllerContext = new ControllerContext(htmlHelper.ViewContext.RequestContext, controllerToLinkTo);
var controllerDescriptor = new ReflectedControllerDescriptor(controllerToLinkTo.GetType());
var actionDescriptor = controllerDescriptor.FindAction(controllerContext, actionName);
return ActionIsAuthorized(controllerContext, actionDescriptor);
}
private static bool ActionIsAuthorized(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
{
if (actionDescriptor == null)
return false; // action does not exist so say yes - should we authorise this?!
AuthorizationContext authContext = new AuthorizationContext(controllerContext);
// run each auth filter until on fails
// performance could be improved by some caching
foreach (IAuthorizationFilter authFilter in actionDescriptor.GetFilters().AuthorizationFilters)
{
authFilter.OnAuthorization(authContext);
if (authContext.Result != null)
return false;
}
return true;
}
private static ControllerBase GetControllerByName(HtmlHelper helper, string controllerName)
{
// Instantiate the controller and call Execute
IControllerFactory factory = ControllerBuilder.Current.GetControllerFactory();
IController controller = factory.CreateController(helper.ViewContext.RequestContext, controllerName);
if (controller == null)
{
throw new InvalidOperationException(
String.Format(
CultureInfo.CurrentUICulture,
"Controller factory {0} controller {1} returned null",
factory.GetType(),
controllerName));
}
return (ControllerBase)controller;
}
It could use some caching but for my case that was a premature optimization.
What is the problem you are trying to solve? It sounds like you may be headed down a path to a complex solution that could use a simple solution instead.
If a user doesn't have permissions to access the page after login, are you wanting non-logged in users to go to one page, while logged in users go to a different page?
If that's the case I might be tempted to create another controller for just such scenarios and redirect to that controller anywhere the user doesn't have access. Or if you are using your own base Controller I would put the functionality there.
Then the controller could present the desired view. For example if a non-logged in user tries to access a page they could get redirected to a generic error page. If the user is logged in, they could get redirected to a not authorized page.
This is very similar to Robert's answer.
Here's a basic skeleton for a base controller.
public BaseController: Controller
{
... // Some code
public ActionResult DisplayErrorPage()
{
// Assumes you have a User object with a IsLoggedIn property
if (User.IsLoggedIn())
return View("NotAuthorized");
// Redirect user to login page
return RedirectToAction("Logon", "Account");
}
}
Then in lets say a AdminController (that inherits from BaseController) action
public ActionResult HighlyRestrictedAction()
{
// Assumes there is a User object with a HasAccess property
if (User.HasAccess("HighlyRestrictedAction") == false)
return DisplayErrorPage();
// At this point the user is logged in and has permissions
...
}
This is probably going to sound controversial, but I check security at the beginning of each controller method, inside the method:
public class ProductController : Controller
{
IProductRepository _repository
public ActionResult Details(int id)
{
if(!_repository.UserHasAccess(id))
return View("NotAuthorized");
var item = _repository.GetProduct(id);
if (item == null)
return View("NotFound");
return View(item);
}
}
The reason I don't use the [Authorize] attributes for this is that you cannot pass an id, or any other identifying information, to the attribute at runtime.
In my application I have created a custom filter derived from AuthorizeAttribute, so any unauthorized access will simply go to AccessDenied page. For links, I replace Html.ActionLink with a custom helper Html.SecureLink. In this helper extension, I check for this user's roles access to controller/action against database. If he/she have the authorization, return link otherwise return the link text with special remarks (could be image/ coloring/ js)
Why not attribute your controller methods with the security requirement.
I wrote an attribute to do this as follows:
public class RequiresRoleAttribute : ActionFilterAttribute
{
public string Role { get; set; }
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (string.IsNullOrEmpty(Role))
{
throw new InvalidOperationException("No role specified.");
}
if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
filterContext.HttpContext.Response.Redirect(loginUrl, true);
}
else
{
bool isAuthorised = filterContext.HttpContext.User.IsInRole(this.Role);
<< Complete Logic Here >>
}
}
}
i just spent some time implementing #jfar's solution (updating it for non-deprecated GetFilters() version), and then i realized that i can skip this whole thing.
in my case (and i assume most cases) I have a custom AuthorizationAttribute to implement site authorization which in turn calls my authorization service to make the actual access level determinenation.
So in my html helper for generating menu links, i skipped right to the auth service:
#Html.MenuItem(#Url, "icon-whatever", "TargetController", "TargetAction")
public static MvcHtmlString MenuItem(this HtmlHelper htmlHelper, UrlHelper url,string iconCss, string targetController, string targetAction)
{
var auth = IoC.Resolve<IClientAuthorizationService>().Authorize(targetController, targetAction);
if (auth == AccessLevel.None)
return MvcHtmlString.Create("");
*user is determined within the client auth service
public string GetUser() {
return HttpContext.Current.User.Identity.Name;
}
*could also add some behavior for read-only access. it's nice because my auth service takes care of caching so i don't have to worry about performance.

Resources