I am learning a newly created default simple MVC4 web project.
In the index page, I have a link for the user to log on the site with his account. After that he will be redirected to a form to enter new name, new password.
I have this form ready for validation using [Required]. But as sooon as the redirected page is completely loaded, these controls (username and password) were done validated (Field needs be filled in) too.
Here is the code of POST after the user log in with his account
if (ModelState.IsValid && WebSecurity.Login(model.UserName, model.Password, persistCookie: model.RememberMe))
{
return RedirectToCreateUser(returnUrl);
}
// If we got this far, something failed, redisplay form
ModelState.AddModelError("", "The user name or password provided is incorrect.");
return View(model);
and here is the method RedirectToCreateUser
private ActionResult RedirectToCreateUser(string url)
{
if (Url.IsLocalUrl(url))
{
return Redirect(url);
}
else
{
return RedirectToAction("CreateNewUser", "Account");
}
}
finally the CreateNewUser method which is for http GET
public ActionResult CreateNewUser(CreateNewUserModel model)
{
return View(model);
}
and another one for http POST which I think hasn't been accessed yet though.
[HttpPost]
public ActionResult CreateNewUser(CreateNewUserModel model, string url)
{
if (ModelState.IsValid)
{
// Attempt to register the user
try
{
WebSecurity.CreateUserAndAccount(model.UserName, model.Password, null, true);
WebSecurity.Login(model.UserName, model.Password);
return RedirectToAction("CreateUserSuccess", "Account");
}
catch (MembershipCreateUserException e)
{
ModelState.AddModelError("", ErrorCodeToString(e.StatusCode));
}
}
else
{
}
return View(model);
}
your problem is here
finally the CreateNewUser method which is for http GET
public ActionResult CreateNewUser(CreateNewUserModel model)
{
return View(model);
}
You cannot pass an object as a parameter on a get request. Probably that signature should be
public ActionResult CreateNewUser()
{
var model = new CreateNewUserModel();
return View(model);
}
or something similar
The CreateNewUser action is firing on the [HttpPost] and attempting to post with invalid (empty) credentials.
You need to add something to this effect using [HttpGet]:
[HttpGet]
public ActionResult CreateNewUser(CreateNewUserModel model)
{
return View(model);
}
Related
My program was working before. I do not know what changes did I make, but now suddenly my login behaves so weird. Every time I try to access Admin authorized page, it keeps redirecting me to login page, even after I login. Here is my code:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(AlvinCMSExtension.Models.LoginModel model, string returnUrl)
{
string redirectUrl = returnUrl;
string userName = model.UserName;
AlvinCMSExtension.Models.UserProfile user = dbAccount.UserProfiles.Where(m => m.Email.Equals(userName, StringComparison.CurrentCultureIgnoreCase)).SingleOrDefault();
if (user != null)
{
userName = user.UserName;
}
if (ModelState.IsValid && WebSecurity.Login(userName, model.Password, persistCookie: model.RememberMe))
{
return RedirectToAction("LoginRedirectionControl", new { redirectUrl = redirectUrl });
}
// If we got this far, something failed, redisplay form
ModelState.AddModelError("", "The user name or password provided is incorrect.");
return View(model);
}
public ActionResult LoginRedirectionControl(string redirectUrl)
{
string returnUrl = redirectUrl;
if (redirectUrl == null)
{
redirectUrl = User.IsInRole("Admin") ? "/Admin" : "/";
}
return RedirectToLocal(redirectUrl);
}
private ActionResult RedirectToLocal(string returnUrl)
{
if (Url.IsLocalUrl(returnUrl))
{
return Redirect(returnUrl);
}
return RedirectToAction("Home", "Page");
}
And I tried to access this:
[Authorize(Roles="Admin")]
public ActionResult Dashboard()
{
return View();
}
After each successful login, the Redirect(returnUrl) does not take me to the returnUrl, but instead to login page again. The parameter used is: http://localhost:5847/Account/Login?ReturnUrl=%2fAdmin%2fDashboard. I debug the code and the returnUrl is holding /Admin/Dashboard/. I do not know what is happening.
Check if the user has the role "Admin", it may be removed
I'm using MVC4 and I have 2 methods in my controller:
Get Method
public ActionResult Create()
{
var vm = new User
{
Client= new Catastro_Cliente()
Genre = ClienteRepository.GetGenres(),
Type= ClienteRepository.GetTypes()
};
ViewBag.Genre = new SelectList(vm.Genre, "IdGenre", "Genre");
ViewBag.Type= new SelectList(vm.Type, "IdType", "Type");
return View(vm);
}
Post Method
[HttpPost]
public ActionResult CrearUsuario(Catastro_Cliente client)
{
if(Validator(client.document))
{
ModelState.AddModelError("NoDocument", "The document is invalid or not registered");
}
if(ModelState.IsValid)
{
return View();
}
}
Basically, I'm trying keep all the data that the user filled in before the post Method,
I tried with return RedirectToAction("Create"); but it always refreshes the page.
You have to pass back the posted model when you call View. What you need is something like:
[HttpPost]
public ActionResult CrearUsuario(Catastro_Cliente client)
{
if(Validator(client.document))
{
ModelState.AddModelError("NoDocument", "The document is invalid or not registered");
}
if(ModelState.IsValid)
{
// save to database of whatever
// this is a successful response
return RedirectToAction("Index");
}
// There's some error so return view with posted data:
return View(client);
}
Here i want to check the request type,
If request is coming from Redirect() method in my applicaton
Add some message to ViewBag to show on Login page
Else don't add message (where user opens login page directly)
public ActionResult Login()
{
//if(RequestIsARedirect)
//ViewBag.LoginMessage = "Please login to Continue";
return View();
}
Thanks in advance.
Wouldn't it be easier if you'll redirect with a parameter?
return RedirectToAction("Login", "Account", new { returnUrl = this.Request.Url });
Or
return Redirect("/Account/Login?returnUrl=' + this.Request.Url });
Then check that returnUrl parameter:
public ActionResult Login(string returnUrl)
{
if (!String.IsNullOrEmpty(returnUrl))
ViewBag.Message = "Please login to continue";
}
Also, if you'll use the built-it [Authorize] action-filter, it will automatically add the returnUrl as parameter to the login Url when redirecting.
See MSDN
The way to do it without adding extra url params is using TempData, which is The data stored ... for only one request..
http://msdn.microsoft.com/en-us/library/system.web.mvc.viewpage.tempdata(v=vs.118).aspx
The code would be like this then:
public ActionResult EntryPoint()
{
TempData["CameFromEntryPoint"] = true;
return Redirect("Login");
}
public ActionResult Login()
{
if(RequestIsARedirect())
ViewBag.LoginMessage = "Please login to Continue";
return View();
}
private bool RequestIsARedirect()
{
return TempData["CameFromEntryPoint"] != null && (bool) TempData["CameFromEntryPoint"];
}
Hello In my project I have to pass a welcome message with username to the Index Page
Its a MVC3 ASP.Net Razor project
There are two controllers are there; One is Login Controller and the second one is Home Controller. From Login Controller, I have to pass UserName of the Login Person to the view Page.
Login Controller redirect to Another controller called Home Controller .From there I have to pass that value to the view page. That's my issue. I have tried with single controller to view, its working.
I cant use the single controller because Login Controller uses Login Page and Home Controller uses Home Page. Both are separate views.
I have tried Like this, but its not working. Can you suggest a good Method to follow?
Login Controller
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(LoginModel model)
{
if (ModelState.IsValid)
{
if (DataAccess.DAL.UserIsValid(model.UserName, model.Password))
{
FormsAuthentication.SetAuthCookie(model.UserName, false);
return RedirectToAction("Index", "Home" );
}
else
{
ModelState.AddModelError("", "Invalid Username or Password");
}
}
return View();
}
Home Controller
public ActionResult Index()
{
return View();
}
You can try with Session, like
Session["username"] = username;
and for recover in the other controller use
var username = (string)Session["username"]
or in your redirect try with
return RedirectToAction("Index", "Nome", new{ username: username})
but the action of your controller must have as argument the (string username) like
public ActionResult Index(string username)
{
return View();
}
You could retrieve the currently authenticated username from the User instance:
[Authorize]
public ActionResult Index()
{
string username = User.Identity.Name;
...
}
Change the Index() method of Home Controller to this:
[HttpPost]
public ActionResult Index(string username)
{
ViewBag.user=username;
return View();
}
Modify the Login Controller :
if (DataAccess.DAL.UserIsValid(model.UserName, model.Password))
{
FormsAuthentication.SetAuthCookie(model.UserName, false);
return RedirectToAction("Index", "Home",new { username = model.Username } );
//sending the parameter 'username'value to Index of Home Controller
}
Go to the View Page of the Index method of Home Controller and add the following:
<p>User is: #ViewBag.user</p>
And you're done. :)
Use TempData. Its data is available in the next request also.
// after login
TempData["message"] = "whatever";
// home/index
var message = TempData["message"] as string;
I am trying to implement a task action method in my MVC 4 application. Everything works on the back in, but it is not redirecting.
public class AccountController : AsyncController
{
[HttpPost]
[AllowAnonymous]
public async Task<ActionResult> Login(LoginModel model, string returnUrl)
{
var client = new ClientHelper("login");
account = await client.CallActionType<LoginModel, Account>(EnumHelpers.HttpType.Post, model);
if (account != null)
{
validLogin = true;
}
return Redirect(returnUrl); // This is called but the page does not redirect, just sits a load
}
}
I was able to get it working after making the Action I was directing it to an async action as well. I am guessing if you have any async action method redirecting to another then that redirect must be async as well.
Here is just a quick example
public async Task<ActionResult> Login(LoginModel model) {
//You would do some async work here like I was doing.
return RedirectToAction("Action","Controller");//The action must be async as well
}
public async Task<ActionResult> Action() {//This must be an async task
return View();
}
[Authorize]
public class AccountController : 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)
{
// find user by username first
var user = await UserManager.FindByNameAsync(model.Email);
if (user != null)
{
var validCredentials = await UserManager.FindAsync(model.Email, model.Password);
// When a user is lockedout, this check is done to ensure that even if the credentials are valid
// the user can not login until the lockout duration has passed
if (await UserManager.IsLockedOutAsync(user.Id))
{
ModelState.AddModelError("", string.Format("Invalid credentials. Please try again, or contact support", 60));
}
// if user is subject to lockouts and the credentials are invalid
// record the failure and check if user is lockedout and display message, otherwise,
// display the number of attempts remaining before lockout
else if (await UserManager.GetLockoutEnabledAsync(user.Id) && validCredentials == null)
{
// Record the failure which also may cause the user to be locked out
await UserManager.AccessFailedAsync(user.Id);
string message;
if (await UserManager.IsLockedOutAsync(user.Id))
{
message = string.Format("Invalid credentials. Please try again, or contact support", 60);
}
else
{
int accessFailedCount = await UserManager.GetAccessFailedCountAsync(user.Id);
int attemptsLeft = (5 - accessFailedCount);
message = string.Format("Invalid credentials. Please try again, or contact support.", attemptsLeft);
}
ModelState.AddModelError("", message);
}
else if (validCredentials == null)
{
ModelState.AddModelError("", "Invalid credentials. Please try again, or contact support.");
}
else
{
await SignInAsync(user, model.RememberMe);
// When token is verified correctly, clear the access failed count used for lockout
await UserManager.ResetAccessFailedCountAsync(user.Id);
return RedirectToLocal(returnUrl);
}
}
else
{
ModelState.AddModelError("", string.Format("Invalid credentials. Please try again, or contact support", 60));
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> ForgotPassword(ForgotPasswordViewModel model)
{
if (ModelState.IsValid)
{
var user = await UserManager.FindByNameAsync(model.Email);
if (user == null || !(await UserManager.IsEmailConfirmedAsync(user.Id)))
{
// Don't reveal that the user does not exist or is not confirmed
//ModelState.AddModelError("", "The user either does not exist or is not confirmed.");
return RedirectToAction("ForgotPasswordConfirmation", "Account");
}
else
{
var code = await UserManager.GeneratePasswordResetTokenAsync(user.Id);
var callbackUrl = Url.Action("ResetPassword", "Account",
new { UserId = user.Id, code = code }, protocol: Request.Url.Scheme);
string Data = System.IO.File.ReadAllText(Server.MapPath(#"~/documents/email_password_reset.txt"));
AspNetUser oUser = dbPortal.AspNetUsers.Find(user.Id);
// can't use string.format becuase of CSS
Data = Data.Replace("{0}", oUser.Name); // user name
Data = Data.Replace("{1}", callbackUrl); // URL to click
Data = Data.Replace("{2}", DateTime.Now.Year.ToString()); // copyright year
await UserManager.SendEmailAsync(user.Id, "Reset Password", Data);
return RedirectToAction("ForgotPasswordConfirmation", "Account");
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
//
// GET: /Account/ForgotPasswordConfirmation
[AllowAnonymous]
public async Task<ActionResult> ForgotPasswordConfirmation()
{
return View();
}
}
the above solution doesn't work for me