I have initialized method in my base controller class which is called whenever any action method is executed. On every action method, I want to check my session and if it is null it should redirect to the login page.
public class BaseController : Controller
{
protected IDataRepository _appData = new DataRepository();
protected override void Initialize(RequestContext requestContext)
{
base.Initialize(requestContext);
if (SessionFactory.CurrentAdminUser == null)
{
RedirectToLogin();
}
}
}
public ActionResult RedirectToLogin()
{
return RedirectToAction("AdminLogin", "Admin");
}
it's calling this method but not redirecting to admin login method and keeps execution on and call method which is in flow so error will come.
In short i want to check whenever my application session gets null its should rediect to login page and its not convenient to check on all methods.please suggest me some good way.
You're calling RedirectToLogin() which in turn simply returns a RedirectToActionResult that is not being used and does not affect the flow of the action.
Try this instead:
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting();
if (SessionFactory.CurrentAdminUser == null)
filterContext.Result = new RedirectResult(Url.Action("AdminLogin", "Admin"));
}
Alternatively, if you insist on overriding Initialize:
protected override void Initialize(RequestContext requestContext)
{
base.Initialize(requestContext);
if (SessionFactory.CurrentAdminUser == null)
{
requestContext.HttpContext.Response.Clear();
requestContext.HttpContext.Response.Redirect(Url.Action("AdminLogin", "Admin"));
requestContext.HttpContext.Response.End();
}
}
Also, check the [Authorize] filter, it may better suit your needs. See here.
A simpler approach:
public void RedirectToLogin()
{
RedirectToAction("AdminLogin", "Admin").ExecuteResult(this.ControllerContext);
}
Related
I have register a global filter to authorize requests that need a cookie but I have a controller that needs to be public so I add [AllowAnonymous] attribute to the controller methods but my filter still fires and keeps redirecting. I'm not sure the best way to fix this issue.
Do I need to modify my onauthorization method to look for the [AllowAnonymous] attribute?
public class CookieAuthFilter : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
HttpCookie cookie = filterContext.HttpContext.Request.Cookies.Get("token");
if (cookie == null)
{
filterContext.Result = new RedirectResult("/Home/Index");
}
}
}
Do I need to modify my onauthorization method to look for the [AllowAnonymous] attribute?
You could, but it would be simpler just to move your logic so the base OnAuthorize method (which contains the logic to scan for [AllowAnonymous]) is unmodified.
public class CookieAuthFilter : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
return httpContext.Request.Cookies.Get("token") != null;
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
filterContext.Result = new RedirectResult("/Home/Index");
}
}
It is better to use AuthorizeCore to return true if the user is authorized, and use HandleUnauthorizedRequest for the redirect.
OnAuthorization also contains some additional logic to help it deal with output caching that you should leave in place.
Question: Is OnAuthorization called for every request? If not, where can I check for session timeout before Authorize attributes are called?
Background:
I need a way to determine if session exists and has not timed out. I want to do this on every method call for every controller in my app. I need to do this before authorization filters are called because I keep a hashset of permissions in session and my authorize attribute looks at these permissions. I need to do this for every request, regardless of whether an authorize attribute is applied or not.
A couple answers I've read (one cited below) state to override OnActionExecuting in a base controller. This makes sense however I've found OnActionExecuting is not calleed until after AuthorizeCore in the filter attribute is called.
The approach I've arrived at thus far is to check for session in a base controller and check for permission in an authorize attribute.
BaseController.cs:
protected override void OnAuthorization(AuthorizationContext filterContext)
{
// This base does two things:
// 1.) Ensures that Session exists
// 2.) Ensures that the Security object exists and is initalized.
HttpContextBase httpContext = filterContext.HttpContext;
// Check if session exists
if (httpContext.Session == null)
filterContext.Result = Redirect(core.SecurityConstants.SessionTimeoutRedirectURL);
else
{
if(!Security.IsInitialized())
filterContext.Result = Redirect(core.SecurityConstants.PermissionDeniedRedirectURL);
else if (httpContext.Session.IsNewSession) // check if a new session id was generated
{
// If it says it is a new session, but an existing cookie exists, then it must have timed out
string sessionCookie = httpContext.Request.Headers["Cookie"];
if ((null != sessionCookie) && (sessionCookie.IndexOf("ASP.NET_SessionId") >= 0))
{
if (httpContext.Request.IsAjaxRequest())
{
filterContext.HttpContext.Response.StatusCode = 401;
httpContext.Response.End();
}
filterContext.Result = Redirect(core.SecurityConstants.SessionTimeoutRedirectURL);
}
}
}
base.OnAuthorization(filterContext);
}
SecurityAttribute.cs:
public class SecurityAttribute : AuthorizeAttribute
{
public Permission Permission { get; set; }
public SecurityAttribute(Permission permission)
{
Permission = permission;
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
base.AuthorizeCore(httpContext);
return Security.HasPermission(Permission);
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
base.HandleUnauthorizedRequest(filterContext);
//if (filterContext.RequestContext.HttpContext.User.Identity.IsAuthenticated)
//{
filterContext.RequestContext.HttpContext.Response.Redirect(SecurityConstants.PermissionDeniedRedirectURL);
//}
}
}
References
When OnAuthorization method is called?
With ASP.NET MVC redirect to login page when session expires
Maybe following works for you, add it in Global.asax
protected void Application_AcquireRequestState()
{
if (Context.Session!=null && Context.Session.IsNewSession)
{
//do something
}
}
I would like to protect my public method from being called by a user.
Because I'm calling the action from an ajax script I can't use any access modifiers, (private, protected etc).
Also, [HttpPost] doesn't stop the user from doing a fake request.
Anyone got a solution?
Thanks
Create an action filter that allows action methods to be called by AJAX only
namespace MyFilters
{
[AttributeUsage(AttributeTargets.Method)]
public class AjaxOnlyAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (!filterContext.HttpContext.Request.IsAjaxRequest())
{
filterContext.HttpContext.Response.StatusCode = 404;
filterContext.Result = new HttpNotFoundResult();
}
else
{
base.OnActionExecuting(filterContext);
}
}
}
}
Then apply this to the action method
[AjaxOnly]
public JsonResult DoSomething()
{
....
I want to extend the Controller class to check whether a request matches certain criteria.
In particular, I want to check whether the user has been directed from a certain URL using the UrlReferrer proprety.
If the user has not come from a particular URL, it should return a 404 message, or in some cases redirect to a different URL altogether.
I was overriding OnActionExecuting to look like this:
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (!IsAuthenticRequest())
{
return new HttpNotFoundResult();
//or in some cases I want to redirect to a completely different URL.
}
}
But this does not work because its a void method.
How would I go about performing this task?
Thanks,
Mike
Even though the other answer is correct, I don't think it's a good solution for your scenario. I think what you need is a custom Action Filter like this:
public class MyActionFilter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (!IsAuthenticRequest())
{
filterContext.Result = new HttpNotFoundResult();
}
}
}
Then, you can use this filter either at the Controller level (to apply it to all Actions in the Controller) or at the Action level:
[MyActionFilter]
public class HomeController : Controller
{
}
Yes, it's a void method, but inside the filterContext parameter you have a Result property. If the result is filled by the time the OnActionExecuting method finishes, the actual Action method is not even going to be called.
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (!IsAuthenticRequest())
{
filterContext.Result = new HttpNotFoundResult();
}
}
Alternatively, if you want this behavior to be consistent across different controllers, you might want to consider writing a filter instead. To understand more about it, please refer to: http://www.asp.net/mvc/tutorials/older-versions/controllers-and-routing/understanding-action-filters-cs
I've just finished implementing a feature such as this within our primary intranet application. My solution was to create a custom authorize filter as suggested by ataravati above,but to redirect according to certain circumstances.
public class UrCustomFilter:ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (!IsAuthenticRequest())
{
if( cond1 == true)
filterContext.Result = new RedirectToRouteResult(
new RouteValueDictionary { { "controller", "Error" }, {"action", "404NotFound" } });
else{
//do another redirect here
}
}
}
}
I want to centralize authentication that developers are free to worry about the implementation of security.
I dont want to validate the authentication at each request like
public class HomeController : BaseController
{
public ActionResult Home()
{
if (Request.IsAuthenticated == true)
{
return RedirectToAction("Home", "Member");
}
return View();
}
public ActionResult Resources()
{
if (Request.IsAuthenticated == true)
{
return RedirectToAction("Resources", "Member");
}
return View();
}
}
Thanks
You can centralized your credential validation by using a BaseController for all your controller inside your application
public class BaseSupplierFlyersController : BaseController
{
//
// GET: /SupplierFlyers/
public ActionResult Index(string culture)
{
//Some action logic here
return View("Index");
}
}
In your BaseControler
public class BaseController : Controller
{
private bool IsLoged = false;
public BaseController()
: base()
{
}
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (!IsLoged)
{
//Redirection du bad login.
//Affect the Result to cancelled previous Action execution
filterContext.Result = new RedirectResult(string.Concat("~/", ControllerConstants.Error,"/", ActionConstants.BadLogin));
}
base.OnActionExecuting(filterContext);
}
protected override void Execute(RequestContext requestContext)
{
//Validate Credential
ValidateCredential(requestContext);
//Traitement standard
base.Execute(requestContext);
}
private void ValidateCredential(RequestContext requestContext)
{
//Logic to validate credential here
IsLoged = true; //or false
}
}
Each time an Action from a Controller is fired the BaseController will validate credential in Execute method and in OnActionExecuting you can valide if the credential are valid and than take an Action like Redirect to an other page.
Looking at the code you wrote it seems like you are missing Action Filters that are part of asp.net mvc. There is one built in called Authorize that basically requires a request to be authenticated before the controller method is invoked, but creating your own is very simple.
Also in asp.net mvc 3 you can define global filters which will be part of every action invoked on your controllers. You can find some samples here