How to get requested Url before Login - asp.net-mvc

Some Controller-Actions in my page are decorated with the [Authorize] attribute. The forward to the Login page works perfect, but after successful login, I want to forward to the requested url. With Request.UrlReferrer, I get the url where I come from, but how can I get the requested action (which requires the login)?

The Login() action takes a string parameter called returnUrl which will be used when redirecting from the login.
You can add the returnUrl to the ViewBag and return a view.
For Eg:
public ActionResult Login(string returnUrl)
{
ViewBag.ReturnUrl = returnUrl;
return View();
}
The target action uses the posted data to authenticate the user and log in the user using FormsAuthentication. It then redirects the user back to the returnUrl.
[HttpPost]
public ActionResult Login(LoginModel model, string returnUrl)
{
if (//Validation Check)
{
FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
return Redirect(returnUrl); // Redirect to referer
}
ViewBag.ReturnUrl = returnUrl;
ModelState.AddModelError("", "The user name or password provided is incorrect.");
return View(model);
}

Related

Check if user is already logged in via Windows Authentication

I'm using LDAP Authentication in MVC Application.
My Login methods (both GET and POST) looks like as bellow:
[AllowAnonymous]
public ActionResult Login(string returnUrl)
{
//Check if User is Logged in Via Windows Authentication.
ViewBag.ReturnUrl = returnUrl;
return View();
}
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginModel model, string returnUrl)
{
using (HostingEnvironment.Impersonate())
{
if (ModelState.IsValid)
{
// Check with AD
if (Membership.ValidateUser(model.UserName, model.Password))
{
FormsAuthentication.SetAuthCookie(model.UserName, true);
// Create a Profile Information Session on Server.
// Other logic goes here.....
}
}
// If we got this far, something failed, redisplay form
ModelState.AddModelError("", #"The user name or password provided is incorrect.");
return View(model);
}
}
Here, How to check if USER is already logged in via Windows Credentials? Say, If I logged in to my machine and when I access this application then I should directly land on Home page instead of Login page. How to achieve this?
Please help me on this.

How to redirect a user from where He/She just come from after logging in?

I am building a E-Store web app. As a process there will be some actions that needs a user to be Authenticated first then can carry further steps. By default in ASP.Net identity when a user logs in He/She will be redirected to the index Action of the Home controller which is not what i want. I would like to redirect the user from where He/She came from. any idea?
Here is my controller:
[AllowAnonymous]
public ActionResult Login(string returnUrl)
{
ViewBag.ReturnUrl = returnUrl;
return View();
}
//
// POST: /Account/Login
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
if (!ModelState.IsValid)
{
return View(model);
}
// This doesn't count login failures towards account lockout
// To enable password failures to trigger account lockout, change to shouldLockout: true
var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);
switch (result)
{
case SignInStatus.Success:
return RedirectToLocal(returnUrl);
case SignInStatus.LockedOut:
return View("Lockout");
case SignInStatus.RequiresVerification:
return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
case SignInStatus.Failure:
default:
ModelState.AddModelError("", "Invalid login attempt.");
return View(model);
}
}
I am using ASP.Net MVC5 identity.
By default in ASP.Net identity when a user logs in He/She will be
redirected to the index Action of the Home controller which is not
what i want. I would like to redirect the user from where He/She came
from
This assumption is not entirely correct. The requested behavior is actually a default.
If you look at Login action (HTTPGET) you will notice that it has a returnUrl parameter. which is filled by the OWIN middleware when a 401 Unauthorized status code is changed to a 302 redirect onto the login path. returnUrl vallue is assigned to ViewBag.ReturnUrl which is later used to append this value Login postback URL(Login.cshtml view):
#using (Html.BeginForm("Login", "Account", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { #class = "form-horizontal", role = "form" }))
Inside Login (HTTPPOST) action you can notice the same returnUrl parameter which is used to redirect the user to this url in case that Login was successful:
case SignInStatus.Success:
return RedirectToLocal(returnUrl);
So if for example you will place Authorize attribute on About action in Home controller and try to access it by typing in browser http://localhost:.../Home/About (replace ... with a port number) you will be redirected to Login action and once you login successfully you will be redirected to initially requested Home/About action

Can I change the route in my MVC controller depending on if the user is already authenticated?

I set up the following route for my application:
routes.MapRoute("DefaultRedirect",
"",
new { controller = "Account", action = "Login" }
);
In my controller I have:
[AllowAnonymous]
public ActionResult Login(string returnUrl)
{
ViewBag.ReturnUrl = returnUrl;
return View();
}
However if the user is already authenticated I don't want to go to the Account controller and the Login action. Is there some way that I could check for authentication before going to the controller or should I check in the controller and then change to a different controller / action ?
I don't think you can do this in route configuration. Routing occurs before authentication in ASP.NET MVC pipeline so you don't have any context to do a switch in route configuration. You need to return another ActionResult if the user is authenticated.
[AllowAnonymous]
public ActionResult Login(string returnUrl)
{
if(User.Identity.IsAuthenticated)
{
return RedirectToAction("Index", "Home");
}
ViewBag.ReturnUrl = returnUrl;
return View();
}

how can declare returnUrl and pass value to it

in code below , returnUrl is passed to LogOn Action.
where i should declare it and then pass it to LogOn Action? and whats it's value?
[HttpGet]
public ActionResult LogOn(string returnUrl)
{
if (User.Identity.IsAuthenticated) //remember me
{
if (shouldRedirect(returnUrl))
{
return Redirect(returnUrl);
}
return Redirect(FormsAuthentication.DefaultUrl);
}
return View(); // show the login page
and in below "Url" in line10 is undefined.
[HttpPost]
public ActionResult LogOn(LogOnModel model, string returnUrl)
{
if (ModelState.IsValid)
{
if (Membership.ValidateUser(model.UserName, model.Password))
{
MigrateShoppingCart(model.UserName);
FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
if (**Url**.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/")
&& !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\"))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
else
{
ModelState.AddModelError("", "The user name or password provided is incorrect.");
add using System.Web.Mvc on top of your controller.
You also should have reference to this DLL and have added its namespace to the web.config
You shouldn't declare it anythere. It's unnecessary parameter and you don't need it, when call method LogOn directly. Just write ("LogOn", "Account") without returnUrl.
As you can see from its name returnUrl means Url there user will be redirected back, if autorization will be succes. So if unregistered user tryed to call a method (visit a page) which required registration he will be first redirected to LogOn page and after success autorization he will be redirected back on a page he wanted to visite (returnUrl)

asp.net mvc: developing login widget

i need a login widget thar appears on every page:
when user logs in he is redirected to the same page
if login fails user redirects to the same page and see error message
widget is rendered with Html.RenderAction
when submitting login form, i take current page url (with java script) and sent it to server - so I can redirect user to the same page after login
public ActionResult Login(string email, string password, string returnUrl)
{
if (userService.AuthenticateUser(email, password))
{
FormsAuthentication.SetAuthCookie(email, true);
if (!string.IsNullOrEmpty(returnUrl))
return Redirect(returnUrl);
return RedirectToAction("Default");
}
else
{
ModelState.AddModelError("login_fail", "login failed");
if (!string.IsNullOrEmpty(returnUrl))
return Redirect(returnUrl);
return View();
}
}
The problem is when errors happens: i need to show them to user but after redirect from Login action all ModelState data is lost (with errors).
The question is: how can I implement login widget to fulfill all above requirments?
Is AJAX an acceptable solution? This way you always stay on the same page and don't need to redirect. Another option would be to store the error message in TempData so that you can fetch it and show it on the redirected page:
public ActionResult Login(string email, string password, string returnUrl)
{
if (userService.AuthenticateUser(email, password))
{
FormsAuthentication.SetAuthCookie(email, true);
if (!string.IsNullOrEmpty(returnUrl))
{
return Redirect(returnUrl);
}
return RedirectToAction("Default");
}
if (!string.IsNullOrEmpty(returnUrl))
{
TempData["message"] = "login failed";
return Redirect(returnUrl);
}
ModelState.AddModelError("login_fail", "login failed");
return View();
}
Also for security reasons it is important to verify that returnUrl belongs to your domain before redirecting or a hacker could create a link and a returnUrl pointing to some spoofing site that looks exactly the same as your and which tricks the user into putting his username and password once again. The default ASP.NET MVC template in Visual Studio suffers from this same vulnerability.

Resources