I am troubleshooting a ASP.NET MVC application and on one server the OnActionExecuting is not firing. It has been a long time since I looked at filters. What can keep the OnActionExecuting from running? The effect in our application is the user context never really gets set up (Initialize)... so everything redirects the user back to the login page.
Here is the code of the filter. Note "Jupiter" was the codename of the project
public class JupiterAuthenticationFilter : IActionFilter
{
private readonly IJupiterContext _jupiterContext;
public JupiterAuthenticationFilter(IJupiterContext jupiterContext)
{
if (jupiterContext == null)
{
throw new ArgumentNullException("jupiterContext");
}
_jupiterContext = jupiterContext;
}
public void OnActionExecuting(ActionExecutingContext filterContext)
{
_jupiterContext.Initialize();
}
public void OnActionExecuted(ActionExecutedContext filterContext)
{
}
}
It can happen when your Controller has System.Web.MVC implementation, but ActionFilter has System.Web.Http.
Related
I have a ASP.Net MVC5 application. I disabled caching through out the application by applying global filter as follows:
public class CachingFilter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
filterContext.HttpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache); // HTTP 1.1.
filterContext.HttpContext.Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);
filterContext.HttpContext.Response.Cache.AppendCacheExtension("no-store, must-revalidate");
filterContext.HttpContext.Response.AppendHeader("Pragma", "no-cache"); // HTTP 1.0.
filterContext.HttpContext.Response.AppendHeader("Expires", "0"); // HTTP 1.0.
}
}
The filter above disables caching brilliantly. But now I have an action to populate some statistics as a PartialView. For test purposes I wanted to enable caching for 20 seconds, by applying OutputCacheAttribute as follows:
[AcceptVerbs(HttpVerbs.Get)]
[OutputCache(Location = OutputCacheLocation.Client, Duration = 20, VaryByParam = "*")]
public PartialViewResult Statistics()
{
var stats = GetStatistics();
return PartialView("~/Views/Shared/_Statistics.cshtml", stats);
}
No matter what I did, If CachingFilter is enabled in application global, Statistics() method is always called even though 20 second period isn't elapsed. If I disable CachingFilter from global, Statistics() method is cached properly.
I thought/read that applying cache filter to action is the final verdict for caching. How to bypass global caching properties in action level without adding action/controller name in if clauses in global cache filter?
You can create your own attribute to exclude the global filter on certain attributes, for example, create a stub attribute:
public class ExcludeCacheFilterAttribute : Attribute
{
}
Now in CachingFilter check for this attribute before running your code:
public class CachingFilter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.ActionDescriptor.GetCustomAttributes(typeof(ExcludeCacheFilterAttribute), false).Any())
{
return;
}
//Carry on with the rest of your usual caching code here
}
}
I'm building the below filter:
public class TestflowFilter : FilterAttribute, IActionFilter
{
public void OnActionExecuted(ActionExecutedContext filterContext)
{
var profileId = int.Parse(ClaimsPrincipal.Current.GetClaimValue("UserId"));
var appId = int.Parse(filterContext.RouteData.Values["id"].ToString());
if (profileId != 0 && appId != 0)
{
if (CheckIfValid(profileId, appId))
{
// redirect
filterContext.Result = // url to go to
}
}
}
public void OnActionExecuting(ActionExecutingContext filterContext)
{
}
}
I actually only need OnActionExecuted, but since IActionFilter is an interface I have to implement them both. Is it ok to leave OnActionExecuting blank if I don't need anything to happen, or do I need to call a base version that MVC always runs?
Also in the OnActionExecuted method if the CheckIfValid is true I redirect the user, but if not I don't do anything. Is that ok or do I need to set some property on the filterContext instead.
I actually only need OnActionExecuted, but since IActionFilter is an interface I have to implement them both. Is it ok to leave OnActionExecuting blank if I don't need anything to happen, or do I need to call a base version that MVC always runs?
Leaving the method body empty is perfectly acceptable in this case. Looks good!
Also In the OnActionExecuted method if the CheckIfValid is true I redirect the user, but if not I don't do anything, is that ok or do I need to set some property on the filterContext instead.
Your filter is fine. MVC does offer a different abstract base class called ActionFilterAttribute, which implements these interfaces for you to override as needed. There's a nice overview that you can read about here. If you derive from that class, your filter attribute code could be simplified a little bit:
public class TestflowFilter : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
var profileId = int.Parse(ClaimsPrincipal.Current.GetClaimValue("UserId"));
var appId = int.Parse(filterContext.RouteData.Values["id"].ToString());
if (profileId != 0 && appId != 0)
{
if (CheckIfValid(profileId, appId))
{
// redirect
filterContext.Result = // url to go to
}
}
}
}
I want to call controller method in Global.asax. Code is given below.
protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{
if (User.Identity.IsAuthenticated)
{
//here we can subscribe user to a role via Roles.AddUserToRole()
}
}
This event is in global.asax. I want to call controller method which return user permissions from database. How this is possible to call controller method here after that I will save user permissions in session and my controller constructor? Code is given below.
public class AccountController : Controller
{
private readonly ISecurityService securityService;
public AccountController(ISecurityService securityService)
{
this.securityService = securityService;
}
}
Please guide me.
You could handle this using a custom AuthorizeAttribute. This allows you to place an attribute on the top of any controllers / methods which you require authentication to be successful in order to call. This lets you override AuthorizeCore which you can then use to do any custom authorization you want to perform. You can also save any other information to session from this method.
For example:
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
// do your own athorization stuff here
}
}
Then you can decorate you controllers that require the use of this authorization either with your attribute:
[CustomAuthorize]
public class AccountController : Controller
{
}
Or using a base controller:
[CustomAuthorize]
public class BaseAuthController : Controller
{
}
public class AccountController : BaseAuthController
{
}
i Resolve this issue by my self i call service method in global.asax by resolving dependency issue below is the solution of the above problem.
protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{
if (User.Identity.IsAuthenticated)
{
IUnityContainer container = GetUnityContainer();
ISecurityService securityService = container.Resolve<SecurityService>();
var list = securityService.GetUserRolesandPermissions("1");
}
}
Thank you every one.
In my asp.net mvc3 application, I have a custom Authorization Attribute as seen below.
public class CustomAuthorize : AuthorizeAttribute
{
public IAccountRepository AccountRepository { get; set; }
public CustomAuthorize()
{
this.AccountRepository = new UserModel();
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
base.AuthorizeCore(httpContext);
return AccountRepository.isEnabled(HttpContext.Current.User.Identity.Name);
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
base.HandleUnauthorizedRequest(filterContext);
}
}
I have the [CustomAuthorize] tag on my controller actions, and the AuthorizeCore method works fine - it performs the logic I want it to (making sure the account is actually enabled), and then returning as such.
However, the overridden HandleUnauthorizedRequest method, which as I understand it should allow me to control the behaviour of an unauthorized request, is not running at all. I put a breakpoint there, I put code in there, I access my application unauthorized, and the code never runs.
What am I missing?
EDIT: I did some more research and found a few other people who had this problem, but no solution unfortunately.
EDIT2: Sample code
[CustomAuthorize]
public class UserController: Controller
{
public UserController()
{
//do stuff here
}
}
EDIT 3: #Fabio
Here's what I'm trying to do. I have a login page (forms auth) that works fine - it calls my custom login, and then calls my AuthorizeCore override. My application uses a large amount of ajax calls, and my eventual goal is for whenever a user is using the application, and the administrator disables them, making an ajax call after being disabled (though still being logged in) should log them out. However, in order to do this, i want to return a custom response if the user is making an ajax call, and for that, I need to ovverride HandleUnauthorizedRequest. But my Authorize Core (and by extension HandleUnauthorizedRequest) are being ignored if the user is logged in (despite the fact that I have customauthorize tags on all of my controller actions that the ajax is calling).
In short: I want to authorize the user on every request, not just the login request (which seems to be what the membership provider is doing right now)
I ended up changing my approach a fair bit. I implemented individual permissions checking, and then that caused AuthorizeCore to be called every time (and not be cached, which I guess was what was happening before).
Interestingly enough, putting a breakpoint on the HandleUnauthorizedRequest override still doesn't break, but putting it inside the method will. Strange, and threw me off for a bit, but I've solved it now.
Code if anyone is interested:
public class CustomAuthorize : AuthorizeAttribute
{
public string Permissions { get; set; }
private IAccountRepository AccountRepository { get; set; }
private string[] permArray { get; set; }
private string reqStatus { get; set; }
public CustomAuthorize()
{
this.AccountRepository = new UserModel();
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
base.AuthorizeCore(httpContext);
if (Permissions != null) {
permArray = Permissions.Trim().Split(' ');
if (AccountRepository.isEnabled(httpContext.User.Identity.Name)) {
this.reqStatus = "permission";
return AccountRepository.hasPermissions(permArray);
} else {
return false;
}
} else {
return AccountRepository.isEnabled(httpContext.User.Identity.Name);
}
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
if (this.reqStatus == "permission") {
filterContext.Result = new RedirectResult(MvcApplication.eM.cause("no_permission", "redirect"));
} else {
base.HandleUnauthorizedRequest(filterContext);
}
}
}
And then I decorated the controller with this:
[CustomAuthorize(Permissions="test_perm")]
This may be a stupid answer/question but is AccountRepository.isEnabled method returning false so that the HandleUnauthorizedRequest can be executed?
If it's returning true, then the HandleUnauthorizedRequest method won't be executed.
Authorization and authentication in MVC application
I have an internal web app developed in C# using MVC 2. I want to use AD roles/groups to do authorization. Thus I have 3 access group Admin, Basic, Readonly. The access to the application will be controlled through these groups.
Now when I hit an action/page of my MVC app, the requirements are:
1) Check level of access (is in either group Admin, Basic or Readonly)
2) If in a group - serve the page.
If not - serve the 401 Unauthorized page.
I am probably confusing myself with the concepts authorization/authentication, but this is how it is set up so far (from answers, google and my own efforts flowing from this question:
public static class AuthorizationModule
{
public static bool Authorize(HttpContext httpContext, string roles)
{
...
//Check Configuration.AppSettings for the roles to check
//using httpContext.User check .IsInRole for each role and return true if they are
...
//other wise throw new HttpException(401,.....)
}
...
}
public class AuthorizeByConfigurationAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
//Essentially at the moment this is pretty much the same as AuthorizationModule.Authorize(HttpContext httpContext, string roles)
}
}
//This code from http://paulallen.com.jm/blog/aspnet-mvc-redirect-unauthorized-access-page-401-page
public class RequiresAuthenticationAttribute : AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
if (filterContext.HttpContext.User.Identity.IsAuthenticated)
{
filterContext.Result = new ViewResult {ViewName = "AccessDenied"};
}
else
{
base.HandleUnauthorizedRequest(filterContext);
}
}
}
The problems with this are that I seem to need to decorate my action methods twice now, ala:
[AuthorizeByConfiguration(Roles = "Admin, Basic, Readonly")]
[RequiresAuthentication(Roles = "Admin, Basic, Readonly")]
public ActionResult Index(string msg)
{
...
}
And the next problem is that it seems I have three separate methods all trying to do the same thing. I am overriding methods based on advice and not entirely sure how they were meant to work originally. How could I go about implementing my requirements?
edit: Since this is an IntrAnet app, all users who sign on with their network accounts will be able to access this app. I need to restrict the access so that only those who belong to certain Active Directory security groups can access this app
I have wrapped all the methods concerning auth with the interface IAuthorization.
Here is an example custom attrbiute you would need to add the Roles property and your own implementaion.
Attribute calls the filter itself for testability reasons.
public class SomeAuthorizeAttribute : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
var filter = new SomeAuthorizeFilter(DependencyLookup.Resolve<IAuthorization>());
filter.OnAuthorization(filterContext);
}
}
public class SomeAuthorizeFilter : IAuthorizationFilter
{
private readonly IAuthorization _authorization;
public SomeAuthorizeFilter(IAuthorization authorization)
{
_authorization = authorization;
}
protected virtual ActionResult ResultWhenNotAuthenticated(AuthorizationContext filterContext)
{
//snip..
//default
RouteValueDictionary redirectTargetDictionary = new RouteValueDictionary
{
{"action", "Index"},
{"controller", "Home"}
};
return new RedirectToRouteResult(redirectTargetDictionary);
}
#region IAuthorizationFilter Members
public void OnAuthorization(AuthorizationContext filterContext)
{
if (!_authorization.GetCurrentUserIdentity().IsAuthenticated)
{
filterContext.Result = ResultWhenNotAuthenticated(filterContext);
}
}
#endregion
}