Password reset in MVC - asp.net-mvc

I have a view at /Account/ResetPassword where the user will provide an email address for the account who's password they want to reset.
The email sent for the password reset will contain a link that looks something like this:
/Account/ResetPassword/{reset key}
I'm not sure how or where to design the view for the creation of the new password though.
It occurred to me to use a partial view that has its master set to the ResetPassword view, but having to name the view confuses me...
The url suggests a dynamic name, so how do I create the View?

I wouldn't bother with the inheritance of the ResetPassword view, you aren't gaining much given it's only a single field. I would create a distinct view for CreatePassword, you can determine which view you want to return based on whether the reset key parameter is provided or not e.g.
public ActionResult ResetPassword(string resetKey)
{
if (String.IsNullOrEmpty(resetKey)) {
return View(); // will return "ResetPassword" view
} else {
// check validity of key then redirect if necessary
return RedirectToAction("CreatePassword");
}
}

I would create /Account/ConfirmResetPassword/{reset key} as the link in the email. If the reset key is correct, then redirect user to another view, let's say /Account/ChangePassword where user can change the password. If the reset key is incorrect, then stay on /Account/ConfirmResetPassword/{reset key} and display a message that the reset key is invalid.
This would be the controller action method for /Account/ConfirmResetPassword/{reset key}
public ActionResult ConfirmResetPassword(string resetKey)
{
bool isResetKeyCorrect = ...; // check if resetKey is correct here.
if (isResetKeyCorrect)
{
// redirect to /Account/ChangePassword
return RedirectToAction("ChangePassword", "Account");
}
else
{
// Display a message saying that the reset key is invalid
.......
return View();
}
}

Related

Pass usercode and returns username with filled field

I am facing some unusual issue on return username..
I am giving brief view,
I am working on web app portal..
I am providing login page..
In login page.. user should enter his login code.. then he get automatically username field fill..just need to enter password and if everything well..he is on dashboard..
I am using entity framework code first approach.. i am facing issue in linq query..
How to validate usercode and return username in filled field and again pass password and validate
You should not put the variable USERCODE in quotes because it will be treated as a string that contains the value "USERCODE".
public ActionResult GETUSERNAME(string USERCODE)
{
Dbconnects con = new Dbconnects();
// LoggedUserName
try
{
var user = con.webusers.FirstOrDefault(x => x.w_usr_code == USERCODE);
if (user != null)
{
}

How can I set the ReturnUrl when I am using RedirectToAction?

I have a controller that redirects to another action, e.g.
mysite.com/food/3
This action does a RedirectToAction to an action called Cake and passes in id=3.
If the user is not authenticated at that point, you go back to the loginpage, but the RedirectUrl is /Cake (without any mention of the id) and not /food/3. This causes an error once you log in because firstly it shouldn't be accessed via that url in the browser, and secondly because the parameters have vanished.
Is there a simple way to make sure it redirects to the original URL in the browser, or do I have to write a custom authorize attribute and store a lookup table to get the parent page?
Gonna take a stab at this one.
Food and Cake take id values and redirect parameters and just pass them around freely where they can be used as you see fit.
Food
public ActionResult Food (int id, string returnUrl = string.Empty)
{
// Do work
return RedirectionToAction("Cake", new { id, returnUrl })
}
Cake
[Authorize]
Cake (int id, string returnUrl = string.Empty)
{
// Do work
if (returnUrl != string.Empty)
return Redirect (returnUrl);
return View();
}
A problem arises when a View is finally returned to the client because then you have to somehow get that returnUrl into the form posted when they submit their login info because you want to use it later. So the first step is getting it into the View's form so it's included in the model that gets posted. One way to do that is the ViewBag; another way is pulling it from the query string. I've shown an example of both below.
Option 1:
Login
Login (string returnUrl = string.Empty)
{
ViewBag.ReturnUrl = returnUrl;
return View();
}
Login.cshtml
Model.ReturnUrl = ViewBag.ReturnUrl;
Option 2:
Login
Login ()
{
return View();
}
Login.cshtml
Model.ReturnUrl = Request.QueryString["ReturnUrl"];
If this doesn't suffice, comment and I can try to modify this answer further.
The simplest way to make this work is to put the AuthorizeAttribute onto the action method that calls RedirectToAction to short circuit the nonsense of building the wrong URL. The FormsAuthenticationModule uses the RawUrl of the request when it adds the ReturnUrl parameter, so it not possible to modify without building your own custom FormsAuthenticationModule (which you could consider option B). But if you check authorization before you redirect the RawUrl will be correct.
// This ensures it builds the correct ReturnUrl.
[Authorize]
public ActionResult Food (int id)
{
// Do work
return RedirectionToAction("Cake", new { id = id })
}
// This ensures the final destination cannot be accessed
// without authorization.
[Authorize]
public ActionResult Cake (int id)
{
// Do work
return View();
}

Error message position in mvc razor

I'm trying to put custom error messages for a login and registration forms.
So far I have the form to check if there's an email already registered, if it is, it will return
Response.Write("There's already someone with that email")
But the problem with this is that the message will only appear on the top of the website.
Is there a way I could display these error messages somewhere else?
I know that in the model I could just put
[Required(ErrorMessage = "Something here")]
And then just put in the view somewhere
#Html.ValidationMessageFor(a =>a.Email)
and it will display the error there.
The code that I have for now is this:
[HttpPost]
public ActionResult Register(Registration signingUp)
{
var db = new ShareRideDBEntities();
if (ModelState.IsValid)
{
//find if email is already signed up
var FindEmail = db.tblProfiles.FirstOrDefault(e => e.PROF_Email == signingUp.Email);
//if email is not found up do this
if (FindEmail == null)
{
var Data = db.tblProfiles.Create();
Data.PROF_Password = signingUp.Password;
Data.PROF_Email = signingUp.Email;
db.tblProfiles.Add(Data);
int Saved = db.SaveChanges();
if (Saved != 0)
{
Response.Write("Registration Successful.");
}
else
{
Response.Write("There was an error.");
}
}
else
{
Response.Write("There's already an user with that email.");
return View();
}
}
else
{
Response.Write("Fill all the fields to continue.");
}
return View();
Now if I do this with an existing email it will return "There's already an user with that email." but it will be display on the top of the website.
How can I make this error message be displayed somewhere else?
I heard something with #Html.Raw() but I'm confused on how to use it.
Using this.ModelState.AddModelError method you can add any custom error message you want. If you specify property name as a key - it will be displayed by corresponding ValidationMessageFor. So in controller instead of writing to response directly do this:
ModelState.AddModelError("Email", "There's already an user with that email.");
return View();
And in view this line which you already have:
#Html.ValidationMessageFor(a =>a.Email)
will display this messagea at whatever part of the page you place it (presumably near the field for email).

Pass Value from View To Controller in Asp.net MVC

I am trying to pass a message to another view (actually same controller) I can do it well but there is a problem for me..
I am new on web and it doesnt seem good ..
and here my c# code
if (createStatus == MembershipCreateStatus.Success)
{
string registrationMessage = "You have registered successfully";
return RedirectToAction("KurumsalGiris", new { message = registrationMessage });
}
[AllowAnonymous] //sonradan eklendi
public ActionResult KurumsalGiris(string message="")
{
if (User.Identity.IsAuthenticated)
return Content("Zaten giriş yapmışsınız");
ViewBag.RegistrationMessage = message;
return View();
}
and here html side
#model E_Cv.Models.LogOnModel
#{
ViewBag.Title = "Kurumsal Giriş";
}
<h2>Kurumsal Giriş</h2>
<h2>#ViewBag.RegistrationMessage</h2>
<p>
Please enter your user name and password.
#Html.ActionLink("Yeni Kurum Kaydı", "KurumsalKayit")
if you don't have an account.
</p>
so I dont know how to pass value to another view with different way.. I dont want to show this kind of message on address bar and user musnt change it.
Secondly Could I do it with "Get" Method?
Why don't you just return a different view rather than redirecting? In fact, the code the posted in the first place should be posting to a controller that returns a view for a successful login.
In fact, why are you redirecting to a page that asks the user to login if they've just logged in?
Other possible options include encrypting the string in the URL, or just passing a flag in the URL that the controller translates into the corresponding string.
What you would do is instead of returning a RedirectToAction
you could return the View directly: (second parameter is a model, where you can use the same model class E_Cv.Models.LogOnModel adding a RegistrationMessage property to it)
return View("<name of the view>",
new E_Cv.Models.LogOnModel {
RegistrationMessage = "You have registered successfully"
});
or keep the data in the ViewBag like you have done:
ViewBag.RegistrationMessage = "You have registered successfully";
return View("<name of the view>");
regarding your last question, give the message is showing in your URL, you are using the GET method, if you return a View instead of a redirect, it'll avoid showing anything in the URL
You should use TempData in this scenario
if (createStatus == MembershipCreateStatus.Success)
{
TempData["Message"] = "You have registered successfully";
return RedirectToAction("KurumsalGiris");
}
And then in your view
#if (TempData["Message"] != null)
{
<h2>#TempData["Message"]</h2>
}
Or if you want to do it in the controller, just keep your view the same as it is at the moment and set ViewBag.RegistrationMessage in the controller
ViewBag.RegistrationMessage = TempData["Message"];
If the question is how to pass data between controllers without using the querystring, then one option is the Session object.
if (createStatus == MembershipCreateStatus.Success)
{
Session["Message"] = "You have registered successfully";
return RedirectToAction("KurumsalGiris");
}
[AllowAnonymous] //sonradan eklendi
public ActionResult KurumsalGiris(string message="")
{
if (User.Identity.IsAuthenticated)
return Content("Zaten giriş yapmışsınız");
ViewBag.RegistrationMessage = (string) Session["Message"];
return View();
}
However, I agree with #Jonathan Wood below that this is not necessarily the best approach to the particular problem you are attempting to solve. Still, as a general technique, it is worth knowing about.

2-Step Authentication in ASP.Net MVC

I am working on an ASP.Net Mvc 3 application using FormsAuthentication with a custom MembershipProvider (so I do have some control over what the provider returns).
The requirements mandate a 2-step authentication process (username and password followed by secret question). A user should not be able to access any of the "secure" sections of the site without passing both steps. Please don't mention whether this is multi-factor security or not, I already know.
Please provide a recommendation on how to best accomplish this task.
Here are some considerations:
I am allowed (architecturally) to use session - would prefer not to.
I would prefer to use the out-of the box [Authorize] ActionFilter for Controllers providing secure content.
The people in charge would like for the url for the 2 steps to be the same: i.e. www.contoso.com/login/. In my attempts at least, this has caused some minor-but-not-insignificant issues when users enter an incorrect answer in the second step (they are not officially logged in, but I need to ensure that I am still working against the half-authenticated user's secret question/answer).
Thanks.
Use a custom View Model in conjunction with hidden form fields. Just make sure it's all done over https.
ViewModel
public LoginForm
{
public string UserName { get; set; }
public string Password { get; set; }
public int SecretQuestionId { get; set; }
public string SecretQuestion { get; set; }
public string SecretQuestionAnswer { get; set; }
}
Action Methods
public ActionResult Login()
{
var form = new LoginForm();
return View(form);
}
[HttpPost]
public ActionResult Login(LoginForm form)
{
if (form.SecretQuestionId == 0)
{
//This means that they've posted the first half - Username and Password
var user = AccountRepository.GetUser(form.UserName, form.Password);
if (user != null)
{
//Get a new secret question
var secretQuestion = AccountRepository.GetRandomSecretQuestion(user.Id);
form.SecretQuestionId = secretQuestion.Id;
form.SecretQuestion = secretQuestion.QuestionText;
}
}
else
{
//This means that they've posted from the second half - Secret Question
//Re-authenticate with the hidden field values
var user = AccountRepository.GetUser(form.UserName, form.Password);
if (user != null)
{
if (AccountService.CheckSecretQuestion(form.SecretQuestionId, form.SecretQuestionAnswer))
{
//This means they should be authenticated and logged in
//Do a redirect here (after logging them in)
}
}
}
return View(form);
}
View
<form>
#if (Model.SecretQuestionId == 0) {
//Display input for #Model.UserName
//Display input for #Model.Password
}
else {
//Display hidden input for #Model.UserName
//Display hidden input for #Model.Password
//Display hidden input for #Model.SecretQuestionId
//Display #Model.SecretQuestion as text
//Display input for #Model.SecretQuestionAnswer
}
</form>
If you're not happy with sending the username and password back to the view in hidden fields to re-authenticate and make sure they're not cheating... you could create a HMAC or something like that to test.
Btw, this question seems like a few questions rolled into one... so just answered how to do 2-step authentication with one view / action method.
I would probably do something where the first step makes them enter a username and password. Check it, if its good, move them along to an authorize flagged view that asks them to put in the answer to the question. If they fail that, sign them out, boot them out, whatever. I don't think this is possible in one view, unless you render a partial view and if they leave without finishing the authentication process, you sign them out and clear their cookie.
----EDIT-----
On second thought, you could do a partial view, just dont formsauth sign them in until they complete the second part of the partial view. Some psuedo code:
public ActionResult Login(){
get username and password off the view
if its valid
render a partial view that asks for the secret answer
if thats valid
forms auth login
else
try again, get booted, or whatever
else
get booted, try again, whatever
}

Resources