Custom Authentication In MVC - asp.net-mvc

I have a custom auth set up so that a user is stored as a session variable. Once they go through the Account/LogIn process I store the details returned from a 3rd party API as a user in the session like this:
Session["User"] = new UserViewModel(result);
I want to check the user is present before every controller action so I have made a BaseController with the following check in it:
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (Session["User"] != null)
base.OnActionExecuting(filterContext);
else
filterContext.Result = new RedirectToRouteResult(new System.Web.Routing.RouteValueDictionary(new { action = "LogIn", controller = "Account" }));
Each of the controllers then inherits from the BaseController so that it redirects to the Log In page if there is no user. I don't inherit from the BaseController for the AccountController so that it doesn't get in an infinite loop of checking and redirecting, but I also want to have specific pages not check for log in. Is there any way to do this, i.e. write an exception rule in the same way that you might have [AllowAnonymous]?

You could use a filter on those methods as:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
public class ActionCheckAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
string controllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName.ToLower().Trim();
string actionName = filterContext.ActionDescriptor.ActionName.ToLower().Trim();
// this is just a sample.. you can implement any logic you want
if (!actionName.StartsWith("your method name") && !controllerName.StartsWith("your controller name"))
{
var session1 = HttpContext.Current.User.Identity.Name;
HttpContext ctx = HttpContext.Current;
//Redirects user to login screen if session has timed out
if (session1 == null)
{
base.OnActionExecuting(filterContext);
filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new
{
controller = "Account",
action = "LogOff"
}));
}
}
}
}
then on the controllers put the attribute as:
[ActionCheck]
public class MyController : Controller
{
public ActionResult Index()
{
return View();
}
}
or on specific action methods as:
[ActionCheck]
public Actionresult SomeMethod()
{
return View();
}

Related

View is rendered even the request is unauthorized

I have an MVC app where I have an Admin area. When user is not logged in I'm redirecting the request to login page with custom AuthorizeAttribute.
public class UserAuthorizeAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var user = AdminGlobals.CurrentUser;
if (user == null || !user.IsActive)
{
return false;
}
return true;
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
var user = AdminGlobals.CurrentUser;
var context = HttpContext.Current;
//Do not redirect if the request is already redirecting
if (context.Response.IsRequestBeingRedirected) return;
if (user == null || !user.IsActive)
{
context.Response.Redirect("/login", true);
}
else
{
context.Response.Redirect("/unauthorized", true);
}
}
}
Controller and action:
[UserAuthorize]
public ActionResult Index()
{
return View();
}
And in the view I have:
Hello #AdminGlobals.CurrentUser.Title
When the application is in debug mode I'm having NullReferenceExceptions for inside the view and also the layout page since it tries to use same variable #AdminGlobals.CurrentUser which is null. I know I can easily prevent this but I cannot understand why the view is rendered when the request is not authorized. Is it possible to use RedirectToAction inside AuthorizeAttribute to prevent rendering of the view?
I'm not sure that using Response in a filter is the way to go. Typically, you leverage the filterContext to perform your redirect. For example:
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
var user = AdminGlobals.CurrentUser;
var context = filterContext.HttpContext;
//Do not redirect if the request is already redirecting
if (context.Response.IsRequestBeingRedirected) return;
var routeData = new RouteValueDictionary(new {
controller = "Home",
action = "Unauthorized"
});
if (user == null || !user.IsActive)
{
routeData = new RouteValueDictionary(new { controller = "Home", action = "Login" });
}
filterContext.Result = new RedirectToRouteResult("Default", routeData);
}
I'm assuming from your code that both actions are on the HomeController; otherwise, update the controller name to the correct value.
"Default," in the constructor for the RedirectToRouteResult object, is the name of the route in your RouteConfig that you want to be applied.
Also, use the HttpContext from the filerContext.

how to check condition if temp data has value in every controller

I am looking for the optimized way of checking if tempdata has value or not in every controller in MVC. I don't want to write in every controller, Where can I write this condition that if temp data has value then show the view else redirect to Login page.
Please create a base controller
public class BaseController : Controller
{
protected override void OnActionExecuting(System.Web.Mvc.ActionExecutingContext filterContext)
{
var id = filterContext.Controller.TempData["id"];
if (id == null)
{
filterContext.Result = RedirectToAction("Index", "Home");
}
base.OnActionExecuting(filterContext);
}
}
After that you have to inherit the base controller on very controller.
public class CheckController : BaseController
{
public ActionResult Index()
{
TempData["id"] = 2;
return View();
}
}
Use base controller in every controller. Then check in base controller that if temp data has value then show the view else redirect to Login page.
Filter code:
public class MyCustomAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
filterContext.Controller.TempData.Add("some key", "some value");
}
}
Action code:
[MyCustom]
public ViewResult Index()
{
string value = TempData["key"] as string;
return View();
}

MVC 5: extending Authorization to redirect to an action

I am trying to lock users that are authenticated but not active in their profile page (specific controller/action). By active, I mean that the authorization process needs to check the db to see if the account is active (just a column with boolean data).
This is what I have tried:
However this is getting into a loop.
The idea is:
if authenticated and active = show the controller/action.
if not authenticated = show login page (forms auth)
if authenticated and not active = show profile page.
public class CustomAuthorize : AuthorizeAttribute
{
private ISADietRepository repository;
public CustomAuthorize()
{
this.repository = new SADietRepository(new SADietEntities());
}
public override void OnAuthorization(AuthorizationContext filterContext)
{
//base.OnAuthorization(filterContext);
if (filterContext.HttpContext.User.Identity.IsAuthenticated)
{
string user = filterContext.HttpContext.User.Identity.Name;
var result = repository.GetVetClinicByEmail(user);
if (!result.IsActive)
{
filterContext.Result =
new RedirectToRouteResult(
new System.Web.Routing.RouteValueDictionary{{"Controller", "SADiet"},
{"Action", "NewCustomer"},
});
}
}
else
{
filterContext.Result =
new RedirectToRouteResult(
new System.Web.Routing.RouteValueDictionary{{"Controller", "SADiet"},
{"Action", "Login"},
});
}
base.OnAuthorization(filterContext);
}
}
Guys I just tried this code below. It works as long as the user is authenticated. If the user is not authenticated, it no longer asks for authentication, it just run the action with no user logged in.
public class CustomAuthorize : ActionFilterAttribute
{
private ISADietRepository repository;
public CustomAuthorize()
{
this.repository = new SADietRepository(new SADietEntities());
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.HttpContext.User.Identity.IsAuthenticated)
{
string user = filterContext.HttpContext.User.Identity.Name;
var result = repository.GetVetClinicByEmail(user);
if (!result.IsActive)
{
filterContext.Result =
new RedirectToRouteResult(
new System.Web.Routing.RouteValueDictionary{{"Controller", "MyAccount"},
{"Action", "Profile"},
});
}
}
base.OnActionExecuting(filterContext);
}
}
I have found the problem.
My second code is correct. The problem is that I replaced the attribute instead of adding the new one to decorate the controller.
I was doing this:
[CustomAuthorize]
public class SADietController : Controller
instead of this:
[CustomAuthorize, Authorize]
public class SADietController : Controller
all sorted!
Pls find the link below that will help to resolve your issue.
ASP.NET MVC 4 custom Authorize attribute - How to redirect unauthorized users to error page?
ASP.NET MVC - How to show unauthorized error on login page?
http://prideparrot.com/blog/archive/2012/6/customizing_authorize_attribute
Custom Authorize Attribute
http://www.tsjensen.com/blog/post/2010/10/16/ASPNET+MVC+Custom+Authorize+Attribute+With+Roles+Parser.aspx
http://mvcsitemap.codeplex.com/workitem/6333
http://code.commongroove.com/2012/04/20/asp-net-mvc-simple-custom-authorization-by-inheriting-from-the-authorizeattribute/

MVC Authorize Roles goes to Login view?

Put the [Authorize(Roles="admin")] on a view, it works as the user is redirected, however, they are always redirected to the login view despite the fact they are already logged in.
How can I change this so it goes to an error page or something similar?
you can create a custom authorize attribute like this
public class CustomAuthorize : AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
base.HandleUnauthorizedRequest(filterContext);
}
else
{
filterContext.Result = new RedirectToRouteResult(new
RouteValueDictionary(new { controller = "Home", action = "UnAuthorized" }));
}
}
}
and use it like this
[CustomAuthorize(Roles="admin")]
Hope this helps
Instead of the duplicate offered I used code from the question: Prevent FormsAuthenticationModule of intercepting ASP.NET Web API responses and modified accordingly:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class AuthorizeCustom : AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
if (filterContext.HttpContext.Request.IsAuthenticated)
{
filterContext.Result = new RedirectResult("/Error/Unauthorized");
}
else
{
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
filterContext.HttpContext.Response.SuppressFormsAuthenticationRedirect = true;
}
base.HandleUnauthorizedRequest(filterContext);
}
}
}
Then just created a view for the "/Error/Unauthorized" route and changed the attribute [Authorize] to [AuthorizeCustom]. Now unauthorized people will be redirected to login as expected and people who aren't in roles are redirected to a custom view.

MVC using Action Filter to check for parameters in URL. stop action from executing

I want to make the following:
when the url doesn't have an instID, i want to redirect to the "Instelling" action
in this controller, every method needs the instID.
[RequiredParameter(parameterName="instID", controllerToSend="Instelling")]
public ActionResult Index(int? instID) {
//if (!instID.HasValue) {
// return RedirectToAction("Index", "Instelling");
//}
var facts = _db.Instellingens.First(q => q.Inst_ID == instID).FacturatieGegevens;
return View(facts);
}
so this is in the controller.
the actionfilter:
namespace MVC2_NASTEST.Controllers {
public class RequiredParameterAttribute : ActionFilterAttribute {
public string parameterName { get; set; }
public string actionToSend { get; set; }
public string controllerToSend { get; set; }
public override void OnActionExecuting(ActionExecutingContext filterContext) {
if (parameterName != string.Empty) {
if (filterContext.ActionParameters.ContainsKey(parameterName) && filterContext.ActionParameters[parameterName] != null) {
string s = "test";
//all is good
} else {
//de parameter ontbreekt. kijk of de controller en de action geset zijn.
if (actionToSend == string.Empty)
actionToSend = "Index";
if (controllerToSend == string.Empty) {
controllerToSend = filterContext.Controller.ToString();
controllerToSend = controllerToSend.Substring(controllerToSend.LastIndexOf(".") + 1);
controllerToSend = controllerToSend.Substring(0, controllerToSend.LastIndexOf("Controller"));
}
UrlHelper helper = new UrlHelper(filterContext.RequestContext);
string url = helper.Action(actionToSend, controllerToSend);
HttpContext.Current.Response.Redirect(url);
//filterContext.HttpContext.Response.Redirect(url, true);
}
}
base.OnActionExecuting(filterContext);
}
public override void OnActionExecuted(ActionExecutedContext filterContext) {
base.OnActionExecuted(filterContext);
}
}
}
the thing is: it does work, however, the action itself first gets executed, THEN the redirect happens. this is not what I wanted.
Perhaps i shouldnt use actionfilters but just add a route?
in this case, how would i redirect the route to another controller if the instID is missing?
Rather than creating an action filter (which runs just before the return of the action method), you could consider changing to an Authorization Filter which would allow you to redirect to an alternative controller & action
Something like this (pseudo code):
public class RequiredParameterAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
// read instID from QueryString
// if instId is null, return false, otherwise true
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
filterContext.result = new RedirectToRouteResult( new { controller = "MyController" , action = "MyAction" } )
}
}
This was the first result on a question I asked on Google, so I'd like to propose a different answer. Instead of doing the redirect from the action assign a redirect to the filterContext.Result like this:
filterContext.Result = new RedirectResult(url);
If the result property of the filterContext is not null then the underlying action will not be executed. Because you're performing a redirect outside the context of the call you will still execute the action method.

Resources