Action Filter to check Session MVC3 - asp.net-mvc-3

I want to create some custom Filters in my application
After successful login i keep logged in user details in a session and want to check the session is expired or not ( If session expired i want to redirect to login page) and i need a filter for this.
public class MyActionFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
SchoolApp.ViewModels.CurrentSessionModel model=(SchoolApp.ViewModels.CurrentSessionModel)HttpContext.Current.Session["mySession"];
if (model == null)
{
//Redirect to Login page
}
else
{
base.OnActionExecuting(filterContext);
}
}
}
But the problem is this will fire for every rquests even while loading Login page . So how can i make a useful filter control that check for session

Looks like you're trying to do wrong things there. Check your web.config file - it should have section like:
<authentication mode="Forms">
<forms loginUrl="http://www.your_domain.com/login" name="cookie_name" defaultUrl="default_url" domain="your_domain" enableCrossAppRedirects="true" protection="All" slidingExpiration="true" cookieless="UseCookies" timeout="1440" path="/" />
</authentication>
If your session is expired (cookie with cookie_name non exists anymore) - user will be automatically redirected to loginUrl
If you still want to use filters - there's solution that allows you to exclude global filter for some controllers/actions:
assuming you have method in global.asax.cs:
private static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
IFilterProvider[] providers = FilterProviders.Providers.ToArray();
FilterProviders.Providers.Clear();
FilterProviders.Providers.Add(new ExcludeFilterProvider(providers));
filters.Add(DependencyResolver.Current.GetService<MyFilter>(), 2); // add your global filters here
}
Call it in your global.asax.cs:
RegisterGlobalFilters(GlobalFilters.Filters);
Filter provider class will look like:
public class ExcludeFilterProvider : IFilterProvider
{
private readonly FilterProviderCollection _filterProviders;
public ExcludeFilterProvider(IFilterProvider[] filters)
{
_filterProviders = new FilterProviderCollection(filters);
}
public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
{
Filter[] filters = _filterProviders.GetFilters(controllerContext, actionDescriptor).ToArray();
if (filters.Select(f => f.Instance).OfType<OverrideExcludeFilter>().Any())
return filters;
IEnumerable<ExcludeFilterAttribute> excludeFilters = (from f in filters where f.Instance is ExcludeFilterAttribute select f.Instance as ExcludeFilterAttribute);
var excludeFilterAttributes = excludeFilters as ExcludeFilterAttribute[] ?? excludeFilters.ToArray();
if (excludeFilterAttributes.FirstOrDefault(f => f.AllFilters) != null)
{
return new Collection<Filter>();
}
var filterTypesToRemove = excludeFilterAttributes.SelectMany(excludeFilter => excludeFilter.FilterTypes);
IEnumerable<Filter> res = (from filter in filters where !filterTypesToRemove.Contains(filter.Instance.GetType()) select filter);
return res;
}
}
ExcludeFilter attribute class:
public class ExcludeFilterAttribute : FilterAttribute
{
private readonly Type[] _filterType;
public ExcludeFilterAttribute(bool allFilters)
{
AllFilters = allFilters;
}
public ExcludeFilterAttribute(params Type[] filterType)
{
_filterType = filterType;
}
/// <summary>
/// exclude all filters
/// </summary>
public bool AllFilters { get; private set; }
public Type[] FilterTypes
{
get
{
return _filterType;
}
}
}
And usage sample:
[ExcludeFilter(new[] { typeof(MyFilter) })]
public ActionResult MyAction()
{
//some codes
}
So this way your filter of type MyFilter won't fire for specified action

Related

Redirect to Login Page if Session expired in ASP MVC net core

I am working in ASP net core MVC Application. My aim is to redirect to the login page if the session expired.
In my case, I am using several ajax call to load a page. Sometimes it is redirecting properly, but sometimes it is not doing so.
public class CheckSessionIsAvailable : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
if (filterContext.HttpContext == null || filterContext.HttpContext.Session.GetString("UserID") == null)
{
//return RedirectToAction("Index", "Login");
filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new
{
controller = "Login",
action = "Index"
}));
}
}
}
Created an action filter CheckSessionIsAvailable and associated it with all the controllers.
[CheckSessionIsAvailable]
public class TestController : Controller
{
public IActionResult Index()
{
return View();
}
}
Am I doing anything wrong while creating Action Filter ?
You can achieve this by using the OnActionExecuting method of IActionFilter by redefining it in our custom class.
First add it to the services:
services.AddControllersWithViews(options =>
{
options.Filters.Add(typeof(RequestAuthenticationFilter));
});
Then create a custom class RequestAuthenticationFilter and define the OnActionExecuting method.
public class RequestAuthenticationFilter : IActionFilter
{
private readonly IHttpContextAccessor _httpContextAccessor;
public RequestAuthenticationFilter(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
/// <summary>
/// OnActionExecuting
/// </summary>
/// <param name="context"></param>
public void OnActionExecuting(ActionExecutingContext context)
{
var session = _httpContextAccessor.HttpContext.Session.Get("UserId");
if (session == null)
{
context.Result = new RedirectToRouteResult(new RouteValueDictionary(new { action = "Login", controller = "Account", area = "Identity" }));
}
}
/// <summary>
/// OnActionExecuted
/// </summary>
/// <param name="context"></param>
public void OnActionExecuted(ActionExecutedContext context)
{
}
}

How to develop action filter controller or action method specific

i was trying to develop a custom action filter which will check cookie is enable or not. if cookie is not enable then redirect use to a specific error page.here is my code.
public class CheckCookieAttribute : FilterAttribute, IActionFilter
{
public string prmAction{get;set;}
public string prmController{get;set;}
public void OnActionExecuting(ActionExecutingContext filterContext)
{
if(filterContext.HttpContext.Request.Cookie["YourCookie"]==null)
{
filterContext.Result = controller.RedirectToAction(prmAction,prmController)
}
}
public void OnActionExecuted(ActionExecutedContext filterContext)
{
//The action filter logic - after
}
}
now i am using like
[CheckCookie(prmAction="MyAction",prmController="MyController")]
due to lack of good knowledge i am not being able to develop attribute driven check for cookie enable or disable.
i want to develop a code in such a way as a result i should not pass any controller name or action name. i like to use code like
[HttpPost]
[CheckCookieAttribute]
public ActionResult Save(Person oPerson)
{
return View();
}
[CheckCookieAttribute]
public class HomeController : Controller
{
public ActionResult Index()
{return View();}
public ActionResult About()
{return View();}
}
}
where i will not provide any name of controller or action name. just guide me what i need to change in my code. thanks
It seems that what you are trying to accomplish is already built into ASP.NET MVC.
I would use the [Authorize] attribute (http://msdn.microsoft.com/en-us/library/system.web.mvc.authorizeattribute(v=vs.108).aspx) where you want to check if the user has a cookie.
If you want to redirect the user to a specific controller/action when the user is not authorized, you can use the following attribute instead:
public class AuthorizeUserAttribute : AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
filterContext.Result = new RedirectToRouteResult(
new RouteValueDictionary(
new
{
controller = "Error",
action = "Unauthorized"
})
);
}
}
See ASP.NET MVC 4 Custom Authorize Attribute with Permission Codes (without roles)
Then you would use it by using:
[HttpPost]
[AuthorizeUser]
public ActionResult Save(Person oPerson)
{
return View();
}
Or if you want exactly what you asked for you can do it this way:
public class CheckCookieAttribute : ActionFilterAttribute, IActionFilter
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.HttpContext.Request.Cookies["YourCookie"] == null)
{
filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary { {"controller", "MyController"}, {"action", "MyAction"}});
}
else
{
base.OnActionExecuting(filterContext);
}
}
public void OnActionExecuted(ActionExecutedContext filterContext)
{
//The action filter logic - after
}
}

How to modify Authorize attribute to allow a group of User Roles in MVC 3

In my MVC3 wep app, I have extended the Authorize attribute like below
public class MyAuthorizeAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (Authenticate.IsAuthenticated() && httpContext.User.Identity.IsAuthenticated)
{
var authCookie = httpContext.Request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie != null)
{
var ticket = FormsAuthentication.Decrypt(authCookie.Value);
var roles = ticket.UserData.Split('|');
var identity = new GenericIdentity(ticket.Name);
httpContext.User = new GenericPrincipal(identity, roles);
}
}
return base.AuthorizeCore(httpContext);
}
public override void OnAuthorization(AuthorizationContext filterContext)
{
if (!Authenticate.IsAuthenticated())
HandleUnauthorizedRequest(filterContext);
base.OnAuthorization(filterContext);
}
In my Actions, I use it like
[MyAuthorize(Roles = "Member,Inspector,SalesRep,Admin,SuperAdmin")]
public ActionResult OrderUpload()
Now, I have to specify each user role in every action. What I would like to do is
specify something like below
[MyAuthorize(Roles = "Member")]
public ActionResult OrderUpload()
and this should allow any User Role that are equal or above "Member". So a "SalesRep" should be allowed, where as "Visitor", who is below the "Member" should not be allowed.
All User Roles are enum with increasing numbers
public enum UserAccountType
{
Visitor = 5,
Member = 10,
Inspector = 15,
SalesRep = 20,
Admin = 25,
SuperAdmin = 30
}
How do I modify MyAuthorizeAttribute to make this work?
Thanks
Here is my working code
public class MyAuthorizeAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (Authenticate.IsAuthenticated() && httpContext.User.Identity.IsAuthenticated)
{
var authCookie = httpContext.Request.Cookies[FormsAuthentication.FormsCookieName];
string[] roles = null;
if (authCookie != null)
{
var ticket = FormsAuthentication.Decrypt(authCookie.Value);
roles = ticket.UserData.Split('|');
var identity = new GenericIdentity(ticket.Name);
httpContext.User = new GenericPrincipal(identity, roles);
}
if (Roles == string.Empty)
return true;
//Assuming Roles given in the MyAuthorize attribute will only have 1 UserAccountType - if more than one, no errors thrown but will always return false
else if ((UserAccountType)Enum.Parse(typeof(UserAccountType), roles[0]) >= (UserAccountType)Enum.Parse(typeof(UserAccountType), Roles))
return true;
else
return false;
}
else
return false;
//return base.AuthorizeCore(httpContext);
}
public override void OnAuthorization(AuthorizationContext filterContext)
{
if (!Authenticate.IsAuthenticated())
HandleUnauthorizedRequest(filterContext);
base.OnAuthorization(filterContext);
}
}
I don't use AuthorizeAttribute but ActionFilter (it's just me and that's how I learned it) but What I would do is add a property on the AuthorizeAttribute that gets updated when the Attribute gets triggered before the Action.
public class MyAuthorizeAttribute : AuthorizeAttribute
{
private string Role = "";
public MyAuthorizeAttribute(string role){
this.Role = role;
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
:
:
:
// now do a check if the Role is authorized or not using your enum.
// return error page if not
if(RoleisAuthorized)
return;
else
// error page
}
public override void OnAuthorization(AuthorizationContext filterContext)
{
:
:
:
}
}
Now after you got the Role, go get it from the enum and compare if the role is allowed to access the page or not, if not return an error page. So since I'm not familiar with OnAuthorization, I would place the process inside AuthorizeCore.

Defining authentication requirements in MVC3 by action method attribute

I've got an MVC3 application with 4 levels of authentication, and 4 base controllers that tie to each one:
Unauthenticated - BaseController
User - BaseAuthController : BaseController
Advisor - BaseAdvisorController : BaseAuthController
Admin - BaseAdminController : BaseAuthController
Right now I have a series of overrides in place for special cases... e.g. a controller that is typically only for admins can have an action method or two that advisors can use... I have the overrides defined as strings in an array.
public class BaseAuthController : BaseController
{
/// <summary>
/// Enter action names in here to have them ignored during login detection
/// </summary>
public string[] NoAuthActions = new string[] { };
/// <summary>
/// Actions only usable by Users+
/// </summary>
public string[] UserOnlyActions = new string[] { };
/// <summary>
/// Actions only usable by Advisors+
/// </summary>
public string[] AdvisorOnlyActions = new string[] { };
/// <summary>
/// Actions only usable by Admins+
/// </summary>
public string[] AdminOnlyActions = new string[] { };
.......
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
//special code here to determine what to do with requested action...
//verifies that user is logged in and meets requirements for method...
//if not, redirects out to another page...
}
}
At the controller level I have them defined like this...
public class GrowerController : BaseAdminController
{
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
UserOnlyActions = new string[] { "GrowthStageSelection" };
AdvisorOnlyActions = new string[] { "Landing", "SeedSelection", "UpdateProjection",
"NitrogenApplications", "DeleteNitrogen", "MassUpload",
"VerifyHolding", "ConfirmHolding", "DeleteHoldingDir", "DeleteHoldingFile" };
base.OnActionExecuting(filterContext);
}
//......
[HttpPost]
public ActionResult GrowthStageSelection(int growerID, int reportGrowthStageID = 0)
{
//code...
}
}
This system has actually worked out pretty well for us, but the problem for me has been that it feels messy. You have to define the methods one place, and override their authentication level elsewhere if necessary. If you change the method name you have to remember to change it elsewhere.
What I'd LOVE to be able to do is decorate the methods themselves with authentication specific attributes and do away the string-based definitions (or at least make them transparent and use List<string> dynamically or something). Here's an example of what I'm looking for...
[HttpPost]
[AdvisorAuthentication]
public ActionResult GrowthStageSelection(int growerID, int reportGrowthStageID = 0)
{
//code...
}
Problem is that I can't find a good way to achieve this with attributes. I've tried creating subclasses of ActionFilterAttribute but they run after my BaseAuthController's override for OnActionExecuting. At that point it's too late in the game to add new methods to the string lists dynamically, and moreover I can't even seem to access the current controller instance from the attributes.
Maybe this whole idea is off base. Can anyone point me in the right direction? Thanks.
Final solution
First, I went ahead and deleted all of my special controllers except for BaseController - I had no use for them anymore. I moved the current special authentication code from BaseAuthController into BaseController. Next, I defined a series of attributes for each of my authentication states:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class BaseAuthAttribute : Attribute
{
public AuthLevels AuthLevel { get; protected set; }
public BaseAuthAttribute(AuthLevels level)
{
this.AuthLevel = level;
}
public override string ToString()
{
return string.Format("Auth Required: {0}", this.AuthLevel.ToString());
}
}
public class UnauthenticatedAccess : BaseAuthAttribute
{
public UnauthenticatedAccess()
: base(AuthLevels.Unauthenticated)
{
}
}
public class UserAccess : BaseAuthAttribute
{
public UserAccess()
: base(AuthLevels.User)
{
}
}
public class AdvisorAccess : BaseAuthAttribute
{
public AdvisorAccess()
: base(AuthLevels.Advisor)
{
}
}
public class AdminAccess : BaseAuthAttribute
{
public AdminAccess()
: base(AuthLevels.Admin)
{
}
}
Then in my BaseController I modified the OnActionExecuting to check the current auth level of the logged in user (if any) against the attribute. This is much cleaner than it was before! (Note: SessionUser and AuthLevels are custom objects for our project - you won't have those)
public partial class BaseController : Controller
{
/// <summary>
/// Override security at higher levels
/// </summary>
protected bool SecurityOverride = false;
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
BaseAuthAttribute authAttribute = filterContext.ActionDescriptor.GetCustomAttributes(false).OfType<BaseAuthAttribute>().FirstOrDefault();
if (authAttribute == null) //Try to get attribute from controller
authAttribute = filterContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes(false).OfType<BaseAuthAttribute>().FirstOrDefault();
if (authAttribute == null) //Fallback to default
authAttribute = new UnauthenticatedAccess(); //By default, no auth is required for base controller
if (!SessionUser.LoggedIn
&& authAttribute.AuthLevel == AuthLevels.Unauthenticated)
{
SecurityOverride = true;
}
else if (SessionUser.LoggedIn
&& SessionUser.LoggedInUser.AuthLevel >= (int)authAttribute.AuthLevel)
{
SecurityOverride = true;
}
if (!SessionUser.LoggedIn && !SecurityOverride)
{
//Send to auth page here...
return;
}
else if (!SecurityOverride)
{
//Send somewhere else - the user does not have access to this
return;
}
base.OnActionExecuting(filterContext);
}
// ... other code ...
}
That's it! Now just put it to use like so...
[AdminAccess]
public class GrowerController : BaseController
{
public ActionResult Index()
{
//This method will require admin access (as defined for controller)
return View();
}
[AdvisorAccess]
public ActionResult Landing()
{
//This method is overridden for advisor access or greater
return View();
}
}
If I understood your question properly, you can implement your own custom attributes (not authorisation attributes) and in the overriden OnActionExecuting of the base controller, you can retrieve the custom attributes of the executing method and based on wich ones are defined you can take appropriate actions. So if a method has the [AdvisorAuthentication] you know that you need to check for those credentials before proceeding.
EDIT:
I don't have an example to point you to as this is something I have implemented in one of my projects. I have no access to that code now but here is an outline:
protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
base.OnActionExecuted(filterContext);
IEnumerable<MyCustomAttribute> attributes = filterContext.ActionDescriptor.GetCustomAttributes(false).OfType<MyCustomAttribute>();
foreach (MyCustomAttributeobj in attributes)
{
switch(MyCustomAttribute.AttribType){
case MyCustomeAttribute.AdvisorAuthentication:
break;
case MyCustomeAttribute.AdminAuthentication:
break;
}
}
}
You can implement just one custom attribute MyCustomAttribute and have it accept a parameter to indicate which authorization type you want. Like that the use of the attribute becomes [MyCustomAttribute("MyCustomeAttribute.AdminAuthentication")]
You can create different Authorize attributes extending IAuthorizationFilter and FilterAttribute something like this
public sealed class AuthenticateAdvisorAttribute : IAuthorizationFilter, FilterAttribute
{
public void OnAuthorization(AuthorizationContext filterContext)
{
//advisor specific logic goes here
}
}
public sealed class AuthenticateAdminAttribute : IAuthorizationFilter, FilterAttribute
{
public void OnAuthorization(AuthorizationContext filterContext)
{
//admin specific logic goes here
}
}
And then you can apply those attributes wherever you require to controller classes/actions
as
[AuthenticateAdmin]
public class AdminController : Controller
{
}
[AuthenticateAdvisor]
public class AdvisorController : Controller
{
}

session becoming null in MVC AuthorizeAttribute

I am using an AuthorizeAttribute to check that users have an over 18 age cookie set to access pages.
This works fine, but I am extending in slightly now.
As all Views use this Attribute, I am using it to allow me to launch my site early.
If uses add ?VIEWSITE=true to any URL, it will set a Session variable, and allow them access to the site. Otherwise, they get directed to a holding page.
This works fine first time the page runs. But, I am using output caching on the page, and the next time the page loads, my httpcontext.session is null?
I've added an "Order" varible to my attributes to ensure they execute in the correct order:
[OfAge(Order = 1)]
[OutputCache(Order = 2, Duration = 2000, VaryByParam = "categoryName")]
Snipit from my Attribute:
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
HttpRequestBase req = httpContext.Request;
HttpResponseBase res = httpContext.Response;
DateTime Live_Date = new DateTime(2011, 07, 01, 07, 0, 0);
if (DateTime.Now > Live_Date || req.QueryString["VIEWSITE"] != null || httpContext.Session["VIEWSITE"] != null)
{
httpContext.Session["VIEWSITE"] = true;
Is there something I am missing here for me to be able to read/set session variables once a page is loaded from cache?
To be clear, it's httpContext.Session that is null, and not specifically httpContext.Session["VIEWSITE"]
3 years down the line and I ran into a similar issue. Now I'm no expert but I believe each controller context call is unique in it's own space, thus httpContext.Session would be null on a new call.
My issue came in the form of a logged in AD user I wanted to store (with his custom application permissions) in a session variable. I'm extending on the AuthorizationAttribute too, but when this filter is applied to a controller action, httpContext is null even though the user was saved.
For people battling with the same issue, the way around this is to create a base controller where this user and it's session state is kept throughout other controllers (inheriting the base controller).
ex.
My Model:
public class LoggedInUser
{
public somenamespace.userclass UserProfile { get; set; }
public List<somenamespace.user_permission_class> UserPermissions { get; set; }
}
My Base Controller:
public class ControllerBase : Controller
{
private LoggedInUser _LoginUser;
public LoggedInUser LoginUser
{
get
{
if (_LoginUser != null)
return _LoginUser;
if (Session["_LoginUser"] == null)
return null;
return Session["_LoginUser"] as LoggedInUser;
}
set
{
_LoginUser = value;
Session["_LoginUser"] = _LoginUser;
}
}
public void PerformUserSetup(string sUsername) // sUsername for testing another user, otherwise User.Identity will be used.
{
sUsername = string.IsNullOrEmpty(sUsername) ? User.Identity.Name : sUsername;
sUsername = (sUsername.IndexOf("\\") > 0) ? sUsername.Split('\\').ToArray()[1] : sUsername;
// Todo - SQL conversion to stored procedure
List<userclass> tmpUser = Root.Query<userclass>(/*sql to select user*/).ToList();
List<user_permission_class> tmpUserpermissions = Root.Query<user_permission_class>(/*sql to select user permissions*/).ToList();
LoggedInUser _LoginUser = new LoggedInUser();
_LoginUser.UserProfile = tmpUser.First();
_LoginUser.UserPermissions = tmpUserpermissions;
LoginUser = _LoginUser;
}
}
My HomeController (standard with any MVC example) :
public class HomeController : ControllerBase
{
[Authorize] // Standard AuthorizeAttribute (AD test)
public ActionResult Index()
{
if (Session["_LoginUser"] == null)
PerformUserSetup("");
return View();
}
}
My Custom permission checking filter which I'll use on any other controller action:
public class PermissionAuthorize : AuthorizeAttribute
{
private readonly string[] permissions;
public PermissionAuthorize(params string[] perms)
{
this.permissions = perms;
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
bool auth = false;
if (httpContext.Session["_LoginUser"] == null)
{
// Do nothing as auth is false.
}
else
{
// Check permissions and set auth = true if permission is valid.
auth = true;
}
return auth;
}
/* not using
public override void OnAuthorization(AuthorizationContext filterContext)
{
var tmp = filterContext.HttpContext.Session;
}
*/
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
// Todo - direct to "unauth page"
base.HandleUnauthorizedRequest(filterContext);
}
}
Usage:
public class Some_OtherController : /*PossibleNamespace?.*/ControllerBase
{
[PermissionAuthorize("somepermission")] // This was a CRUD application thus 1 permission per actionresult
public ActionResult ViewWhatever()
{
....
}
}

Resources