asp.net mvc Custom HandleUnauthorizedRequest - asp.net-mvc

I'm working with asp.net mvc3.
I have a custom AuthorizeAttribute.
I have to override method HandleUnauthorizedRequest(AuthorizationContext filterContext)
My source code is as follows.
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
switch (unAuthorizedStatus)
{
case UnauthorizedStatus.NonAuthenticated:
// I have a question here.
break;
default: base.HandleUnauthorizedRequest(filterContext); break;
}
}
// I have a question here.
If it fails to user authentication(case UnauthorizedStatus.NonAuthenticated), to return to the previous URL,
And I want to show the warning window alert in JavaScript(or jquery).
To answer please.

Are you sure that you need to override the HandleUnauthorizedRequest method?
I followed the approach listed here:http://blogs.msdn.com/b/rickandy/archive/2011/05/02/securing-your-asp-net-mvc-3-application.aspx. Its so good they wrapped it up into MVC4.
Essentially, you handle the OnAuthorization method only. The rest you leave to the base Attribute. That has the nice feature of automatically routing you to the logon page if you are unauthenticated.
If you really want to auto navigate the user back to the original page, you can override the method as you were originally thinking, but instead send the user to a new action method, and pass the return URL from the HttpContext (referring url I think). You can then show a message to the user in html, and then auto navigate the user back to their original page after a couple of seconds wait via a meta refresh.
Your solution wont work if the end user has JS disabled.

Related

FormsAuthentication.RedirectToLoginPage() vs RedirectToAction("Login", "Account")

I am using Forms Authentication in my website. I have seen in some example code that one can call .SignOut() and then use
FormsAuthentication.RedirectToLoginPage()
to send a user to the login page.
What advantage, if any, does this have over calling
RedirectToAction("Login", "Account");
in an MVC website? From MSDN it seems that the former will not call HttpResponse.End() which means that code that follows will execute... I'm not sure when I would need to use this feature.
FormsAuthentication.RedirectToLoginPage() does have some advantage where it will attempt to append ?ReturnUrl={url} to the login page URL which can be used later to return the user to the page they were requesting when the login redirect happened. Using this method uses Response.Redirect() which goes against the MVC mentality. You'll lose out on events like OnActionExecuting from firing in your controller/filters. source code of RedirectToLoginPage
RedirectToAction("Login", "Account"); doesn't have the ReturnUrl feature out of the box, but it does keep everything in the MVC ecosystem so the events fire. In the case if logging someone out and redirecting back to the login page, I'd probably keep it all in MVC and use RedirectToAction. Or potentially use Redirect(FormsAuthentication.Url); if you always want to use the login page URL from the web.config.
Do a SignOut(), but then return a HttpUnauthorizedResult so that the controller will just use it's regular login redirect.
If you are signing out in your OnActionExecuting controller event, do it this way...
protected override void OnActionExecuting(ActionExecutingContext filterContext) {
if (//I need to log out...) {
System.Web.Security.FormsAuthentication.SignOut();
filterContext.Result=new System.Web.Mvc.HttpUnauthorizedResult();
return;
}
base.OnActionExecuting(filterContext);
}

ASP.NET MVC 4 Redirecting the Response in ActionFilterAttribute

so basically I have a custom ActionFilterAttribute and in it I override one method which looks something like this
public override void OnActionExecuting(System.Web.Mvc.ActionExecutingContext filterContext)
{
bool shouldEnter = true;
string redirUrl = "SomeController/SomeAction";
// some checks here which change the value of shouldEnter;
if (!shouldEnter)
{
filterContext.HttpCOntext.Response.Redirect(redirUrl);
}
}
this is a very simple implementation of ActionFilterAttribute. Basically I check something and than decide to let the guy in or not. If I'm not letting him in than I should redirect him to some URL and I do that with the above implementation of OnActionExecuting method. but the thing is that before it goes to the someUrl the action he requested action gets executed first. Suppose I've request the page at ~/SomeController/YouShouldNotEnterHere and this action has that attribute on it. the OnActionExecuting gets invoked and than I suppose that the corresponding action of redirUrl (which is mentioned in OnActionExecuting method ) will get invoked because I redirected the Response to it, but no, first the corresponding Action of /SomeController/YouShouldNotEnterHere gets invoked (but not drawn actually in browser, but the action still consumes time) and than the corresponding action of redirUrl gets invoked (and drawn in browser). Is this some kind of bug? or this is supposed to work this way ? anyway what can I do t
It sounds like you are doing authorization, the proper attribute to use in this case is an AuthorizeAttribute
This will code will fix your existing attribute:
filterContext.Result = new RedirectResult { Url = redirUrl };

MVC Custom Filter to Authorize User and send some response back

I have a special scenario where in I need to authorize all the users to check whether they can execute the controller method or not. If he is not authorized to perform an operation. I need to send back some message back to view to indicate the same. I need to cater below scenario. An item is assigned to an user and only that user can make changes(Assign to others/ Cancel etc..) to that item and others cannot perform it. On the other hand other user can try to first assign than item to themselves and perform operations on it. So the 2 cases which I need to capture is
When a user tries to assign the item to self that is not assigned to him then I need to send some response back to view indicating that the item is locked by XXX user and provide user to override it.
When a user tries to perform other operations on an item that is not assigned to him then just send some message response back to view
I tried creating a custom authorization filter using AuthorizeAttribute and AuthorizeCore, but when the authorization fails it is trying to redirect to Login screen. which I don't need. I need to send back some useful info back.
Hope I am clear. Any help is highly appreciated.
Thanks
I tried creating a custom authorization filter using
AuthorizeAttribute and AuthorizeCore, but when the authorization fails
it is trying to redirect to Login screen. which I don't need.
You could override the HandleUnauthorizedRequest method and return whatever ActionResult you want. For example if you wanted to render an error view you could return a ViewResult:
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
var viewResult = new ViewResult();
viewResult.ViewName = "~/Views/Shared/Unauthorized.cshtml";
filterContext.Result = viewResult;
}

Enforcing a choice prior to viewing MVC and Web Forms pages

I'm working on a system that needs to know a user's choice before they enter a site. Up till now the choice has been stored in a cookie and checked by JavaScript on the page load - if the cookie doesn't exist then a dialog is shown and the user makes the choice.
Although we'd normally expect the user to arrive at the homepage of the application, they can legally follow a URL to any page within the application, so the JavaScript to check the choice exists on every page.
This has caused problems (almost always fixed by clearing cookies) so we're switching to store the choice in the database. What we need is a neat way of making sure that all pages (MVC and Web Forms) check that the choice has been made and, if it hasn't, either display a dialog or redirect to a page where the choice can be made.
The main thing bothering me is that to cause a redirect using MVC, I need to return a RedirectResult, and this can only be done from an Action. I don't want every action to have code regarding this check - it seems like the kind of thing that should be possible from a base controller (in the same way a base page could cause a Response.Redirect.
Can anyone suggest a good way for all pages to perform a check on the database and then either cause a redirect or show a dialog?
The main thing bothering me is that to cause a redirect using MVC, I
need to return a RedirectResult, and this can only be done from an
Action.
Oh not at all. You could also redirect from a custom action filters.
For example you could write a custom IAuthorizationFilter that will check whether the user made the necessary choice and if not redirect to some given page. The check could be done against a cookie, database or wherever you decide to persist this information:
public class EnsureChoiceHasBeenMadeAttribute : FilterAttribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationContext filterContext)
{
// get the current user
var user = filterContext.HttpContext.User;
if (user.Identity.IsAuthenticated && !UserMadeAChoice(user.Identity.Name))
{
// if the current user is authenticated and he didn't made a choice
// redirect him to some page without even attempting to execute
// the controller action that he requested
var values = new RouteValueDictionary(new
{
controller = "home",
action = "index"
});
filterContext.Result = new RedirectToRouteResult(values);
}
}
private bool UserMadeAChoice(string username)
{
throw new NotImplementedException();
}
}
Now you have different possibilities:
You decorate the controllers/actions that you want to perform this check with the [EnsureChoiceHasBeenMade] attribute
You register the action filter as a global action filter so that it applies to absolutely all actions
You write a custom filter provider in order to dynamically apply the action filter to some actions based on some dynamic values (you have access to the HttpContext).

PartialView Render Forms timeout

I'm fetching a partial view via $.ajax() and in the situation where you set idle for 30 minutes and then try to fetch that partial view, the forms authentication has timed out and instead of getting my partial view returned to me, I'm getting the login page render into my .
Any suggestions on how to deal with a situation like this?
Thank you.
$(function () {
$("#addContact").click(function () {
$.get('/Contacts/Add', function (data) {
$("#content").html(data); <--gets login page as data
});
});
});
Does your Add Action have any non-Ajax consumers? If not, I'd suggest removing the [Authorize] attribute from the action, which would remove the timeout-redirect problem. (If you have your entire controller decorated with [Authorize], you'd need to remove the controller-level attribute and adorn all of your other actions. Annoying, I know).
For extra security, you could then do something like this to prevent non-Ajax calls from calling your Add action.
public ActionResult Add()
{
if (Request.IsAjaxRequest())
return View("Error");
return View();
}
If, on the other hand, your Add action needs to support Ajax and normal calls, one way you can address this issue is to create a new Attribute class that inherits from and overrides AuthorizeAttribute. Check out the source for guidance: http://aspnet.codeplex.com/SourceControl/changeset/view/23011#266447
You should be able to do the trick by overriding the AuthorizeCore method, like so
public class AjaxAuthorizeAttribute: AuthorizeAttribute
{
protected override bool AuthorizeCore(System.Web.HttpContextBase httpContext)
{
if (httpContext.Request.IsAjaxRequest())
return true;
return base.AuthorizeCore(httpContext);
}
}
Now you can use [AjaxAuthorize] on your controller and/or action.
To be clear, what you're doing here is giving the user an extension on their timeout if they initiate a call via Ajax. Once they refresh the page, or navigate away, they would be prompted to log back in, as normal.
Hope that helps. Let me know if you run into any issues.
Prior to making the Ajax call, can you make another one to an unauthorized controller to ensure that the user is authenticated? If they are, continue as normal, otherwise you can just show a login lightbox so you don't leave the page and maintain the user experience.
Another solution would be to add some script to your login page to check if it's being rendered within a pop-up. If it is you can use location.href() to redirect the whole page to the login page.
It depends a little on if you're ok with changing the length of time users will be logged in for. If you are, you can change your config file to something like the following...
<authentication mode="Forms">
<forms loginUrl="Login.aspx" timeout="512640" />
</authentication>
This will keep users logged in for one year. If changing the amount of time users are logged in is not an option, you would need to handle the ajax response and redirect users to a login form again.

Resources