How can you have a form that doesn't require the user to be logged in until they click submit, and at that point submits the form if the user is logged in, and otherwise redirects to the login page. Then after the user logs in successfully, submits the original form? The original form has an <input type="file"> element also, and the file shouldn't be uploaded unless the user successfully logs in.
3 Answers
I know this is an old post, hopefully, my experience will help someone:
I have two submit buttons and a common method that gets called for handling form submission from both of them - conditional statements inspect which button is submitting the form.
On the button that requires the user to be authenticated, it was returning HttpUnauthorizedResult() to force the user back to the login page.
After login, the user will just be sent back to the form with field values filled in because they were being stored in a TempData entry, but the user still needed to click the button again to submit the data.
So, I added a boolean TempData variable called AutoSave that will be set right before returning the HttpUnauthorizedResult().
I check it before loading the form again and if AutoSave == true I just redirect to the method that handles the submission.
Works like a charm.
Here's the sample code:
private ActionResult ProcessOnlineApplication(OnlineApplicationViewModel application){
//if not submit make sure it's save.
if (application.SubmitAction == "Save")))
{
if(!User.Identity.IsAuthenticated)
{
//Keep a copy of the application until logged in
TempData["PendingOnlineApplication"] = application;
TempData["AutoSave"] = true;
return new HttpUnauthorizedResult();
}
else{
//Everything goes here
}
}
}
public ActionResult OnlineApplicationForm(){
var viewModel = TempData["PendingOnlineApplication"] as OnlineApplicationViewModel;
if (TempData.ContainsKey("AutoSave") && Convert.ToBoolean(TempData["AutoSave"]) && viewModel != null)
{
TempData["AutoSave"] = false;
return ProcessOnlineApplication(viewModel);
}
if (viewModel == null)
{
viewModel = CreateModel();
}
return GetOnlineApplicationAction(viewModel);
}
Comments
MVC handles this scenario. Just put the "[Authorize]" attribute only on the form post action the one which has the [HttpPost]. On posting the form as the user is not logged in, he will be redirected to Account controller login action(/Account/Login) and login view will be rendered; this is because it is set so in web.config. Along with this redirection a query string parameter "ReturnUrl=/orginalform" is also added. The MVC login action then does the login and redirects the user again to the original form.
Update: Here is the code that should go in the custom attribute that will capture the form data if you need to retain the form data(this is not tested, only compiled)
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
public override void OnAuthorization(
AuthorizationContext filterContext)
{
if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
string loginUrl = "/Account/Login"; //Get this from web.config instead of hardcode
if (filterContext.HttpContext.Request != null)
{
loginUrl += "?ReturnUrl=" + filterContext.HttpContext
.Request
.Url
.AbsoluteUri;
foreach(var formData in filterContext.HttpContext.Request.Form)
{
loginUrl += "&"+formData.ToString();
}
}
filterContext.Result = new RedirectResult( loginUrl );
}
}
}
You may need some modifications into the login post action. Also the return form get action should fetch the form data from the uri string [FromUri] and render the form again.
3 Comments
AuthorizeAttribute and override the OnAuthorization method.