ASP.NET MVC4 WebMatrix WebSecurity Forms authentication: Changing a username - asp.net-mvc

I'm using WebMatrix WebSecurity for my application's Forms Authentication.
The user needs to be able to change his username, without being logged out.
I supposed calling WebSecurity.Logout(), followed by WebSecurity.Login() would do the trick, but Login() requires a password. Of course, I cannot provide this password as it is hashed in the DB.
How can I make this requirement work?
EDIT:
Below are a few suggestions on how to fix the issue of changing the username.
However, my actual problem was that the cookie still holds the old username. I found the following instructions on how to handle that:
http://omaralzabir.com/how_to_change_user_name_in_asp_net_2_0_membership_provider/

So this is how I able to change the user name. This all happens inside a post action method for updating all kinds of user data.
First I check to see if the user name already exists. "info" is a model object coming from the view.
if (WebSecurity.CurrentUserName != info.UserName &&
this.userRepository.Find(info.UserName) != null)
{
ModelState.AddModelError("", "This email is already taken.");
return View();
}
Then I update the database.
UserProfile user = this.userRepository.Find(info.UserId);
user.UserName = info.UserName;
this.userRepository.SaveUser(user);
Then here is the magic part. You have to reset the authorization cookie.
FormsAuthentication.SetAuthCookie(user.UserName, false);
I hope that helps someone out there.

Since WebMatrix WebSecurity is done via UserId, not Username, just change the data in the table you are storing your userdata in, and then redirect them to a new page. You don't need to log them out and back in, I believe the new username will be picked up immediately.

You can do the following steps
Get the UserDetails by UserId or UserName
Change the UserName
Now update the user data by calling the SimpleMembershipProvider.UpdateUser.
More details here

Related

Force a user to re-enter credentials before submit

Using MVC5, i have an application which a user must be logged into, and then can perform standard actions on some data (create, edit, delete).
I would like to add a credentials prompt, whenever a certain task if performed. So say for example a user is editing a row of data. I want them to be prompted to enter their login credentials again when they hit the Save button, before the row is updated. To be clear, they are ALREADY logged in, i just want to force them to re-confirm their credentials before being allowed to save.
How can i do this in the controller? I want a seperate screen/popup to show, asking for username and password (which will then be checked to ensure correct user credentials) before allowing update of the data.
I looked at creating a new method in the controller, which is passed a username and password, which looks after checking the users credentials again. But how do I go about calling this from the Edit screen, when I also need a popup to appear? Do i go down the route of adding a hidden div on the Edit view, which shows when the user clicks the Save button, and it then calls the method?
Generally, you're expected to attempt a solution, first. Then, if you run into specific issues, you can ask a question about those specific issues. I will tell you that this should be relatively straight-forward. All you need is for the user to re-enter their password. Just add a password input to your edit form and bind it to something on your view model, or you can simply bind it directly to an action parameter, in addition to your view model:
[HttpPost]
public ActionResult MyAction(MyViewModel model, string password)
If you want it to be done in a popup, simply include the popup HTML within the form (so the that the input in the popup will be part of the form) or you'll need to use JavaScript to set another input within the form, which would be bound to either a view model property or action param. Either way, the point is that the password should be posted along with the rest of the form data.
Once inside your post action, you can verify the password by manually:
var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
var verifyPassword = UserManager.PasswordHasher.VerifyHashedPassword(user.PasswordHash, password);
if (verifyPassword == PasswordVerificationResult.Failed)
{
ModelState.AddModelError("", "Password incorrect.");
// If password is incorrect, ModelState will be invalid now
}
if (ModelState.IsValid)
{
// save posted data
}
It sounds like you'd ideally want an action which you can call asynchronously from the client. While this can take the form of a standard MVC controller action, you may want to consider building this into a Web API controller (Generally we would use Web API controllers to serve up non-HTML responses). You can read more about Web API in many places on the web so I won't go into that now, but let's say you have a HttpResponseMessage result method which looks like this:
[HttpPost]
public HttpResponseMessage CheckCredentials(string username, string password)
{
// Check user credentials and return either one of the following results:
// If credentials valid
return Request.CreateResponse(HttpStatusCode.OK);
// If not valid
return Request.CreateErrorResponse(HttpStatusCode.BadRequest);
}
Using this pattern you could return a '200 OK' response for valid credentials and a '400 Bad Request' for invalid credentials.
As you already stated, you could have the HTML content required for authentication prompt hidden on the page. When the user performs an action which requires authentication, you could render the popup. When the user submits the popup you could fire off an asynchronous request to the Web API endpoint which you created earlier. Depending on the response you get back, you either proceed with the task or prompt for credentials again with an error message.
Obviously as you'd be sending user credentials over a we request, make sure you're making use of HTTPS.
EDIT:
As Chris mentioned below, this solution leaves your 'quick check' in the hands of the client. While this is fine when you simply want to provide a way to stop the user from easily carrying out an action without re-entering their credentials, you should not rely entirely on it.
You could store the username and password as hidden fields and include them with your main synchronous POST. This would allow you to check that the user entered valid credentials from the server.

How does one prevent duplicate email addresses while users modify their email addresses after registration using the default MVC Membership Provider?

I am using the default ASP.NET MVC Membership Provider and I would like to allow user's to modify their email after they have created their account. I do not want users to be able to use a duplicate email.
How do I allow a user to modify their email and check that the email is not in use elsewhere in the database? I am not sure of the best way to do this type of check when using the default Membership Provider.
note - I know the Membership Provider itself performs this check when a user attempts to register their email address, I do not know how to perform this check at a later time (due to noobness).
note 2 - I only know of this method of accessing the user's email, is this the proper way to be accessing it?
MembershipUser useremail = Membership.GetUser(User.Identity.Name);
ViewBag.Email = useremail.Email;
You can search for an existing username by that email:
String userName = MembershipProvider.GetUserNameByEmail(email)
If no match is found, userName will be null. See here for more info on this.
Also, if your MembershipProvider has RequiresUniqueEmail = true then this check should already be performed for you - as per this page.

asp.net mvc keep object alive, information

i have this code
[HttpPost]
public ActionResult Index(LoginModel loginModel)
{
if (ModelState.IsValid)
{
// some lines of code . bla bla bla
TempData["loginModel"] = loginModel;
return RedirectToAction("index", "premium");
}
...
}
and this controller here
public ActionResult Index()
{
var loginModel = TempData["loginModel"] as LoginModel;
...
}
now, when the page loads, everything seems to work fine. but when i refresh, everything messes up, it says that the loginModel is like null. the question is, how can i like keep track of the current login users. i have forms authentication enabled. tnx
error is as below
Object reference not set to an instance of an object.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.NullReferenceException: Object reference not set to an instance of an object.
Source Error:
Line 22:
Line 23: var loginModel = TempData["loginModel"] as LoginModel;
Line 24: string username = loginModel.username;
Line 25: string password = loginModel.password;
Line 26: premiumModel.username = username;
Confusion
but when i refresh, everything messes up, it says that the loginModel
is like null
Answer
This is due to the fact that you have read the TempData key and Once it is read, data will be lost for that particular key.
var Value = TempData["keyName"] //Once read, data will be lost
Question
how can i like keep track of the current login users
Answer
So to persist the data even after the data is read you can Alive it like below
var Value = TempData["keyName"];
TempData.Keep(); //Data will not be lost for all Keys
TempData.Keep("keyName"); //Data will not be lost for this Key
TempData works in new Tabs/Windows also, like Session variable does.
You could use Session Variable also, Only major problem is that Session Variable are very heavy comparing with TempData. Finally you are able to keep the data across Controllers/Area also.
Hope this post will help you alot.
You only need to store the user's identity (username) once the user is authenticated - password is not needed. As such ASP.NET authentication already supports storing user's identity in the authentication cookie and you don't have to re-invent the wheel. You can get the identity using Controller.User property.
EDIT: I am assuming that you have set up your application correctly for Forms Authentication. Regardless, here are few how-to/tutorial links that start you on it:
http://www.apexa.net/Blog/web_design_Blog_20100319.aspx
http://www.asp.net/mvc/tutorials/authenticating-users-with-forms-authentication-cs
Explain solution so that you don't have to apply Authorize attribute on every action - http://blogs.msdn.com/b/rickandy/archive/2011/05/02/securing-your-asp-net-mvc-3-application.aspx
TempData does only live for one request. Therefore it's empty when you make the second request. If you'd want to do it like this you should use Session instead or you can have a look at forms authentication.
You should also consider VinayC advice and not store any password information in any state, especially not in clear text format.
I suggest you create a new MVC 3 project in Visual Studio via File > New. It will set up forms authentication for you, so you can see the best practices for the login and registration pages, signing the user in/out with the session cookie, and displaying user info like username.

How to use email as httpcontext.User.Identity.name

I'm creating a new asp.net MVC3 app in which in user table I do not wish to have user name but only user id (long) and email (string).
What I would like to understand is normally when I use membership provider with normal db structure, I get the username value in db as the User.Identity.Name.
Could someone please tell me what changes I need to do as I will not have any username in my db to ensure that my email address becomes my User.Identity.Name
Thanks
Arnab
Answer: found out... its FormsAuthentication.SetAuthCookie that decides which value goes to user.identity.name
The value User.Identity.Name typically comes from the "username" you provide the login form. This is stored by the LogOnModel class within the AccountModels model.
To set your email address as User.Identity.Name, you must provide your email address in the username field of the login form. Then use your membership provider to authenticate the user based on the provided email address.
found out... its FormsAuthentication.SetAuthCookie that decides which value goes to user.identity.name

ASP.NET MVC custom membership for beginners

I am creating my own website and blog and I want for first time just me in database (my name and password) and maybe later some registration for others but first log in just for me and administration with authorization. I don´t want to use Membership from MS. I want try to create my own from start so I am looking for guide for beginners but I found big guides with roles, rights. I want just small example with check username, password in database with log on data.
Thanks for help
Libor
Even if you don't want to use the membership and role provider data store you can still utilize the authentication. Trust me, it's a lot easier than building your own. Here's how it works:
We'll say you already have your user storage setup for retrieving the username and their password. For the sake of simplicity I'm going to pretend you have a static class called DataLayer that contains your data retrieval methods for pulling info from the database (or whatever storage you use).
First you need a way to let the user log in. So set up a page with username and password fields. Then in the action method that the page posts to set up a quick if statement:
if (DataLayer.UserExists(userModel.Username))
{
User userFromDB = DataLayer.GetUser(userModel.Username);
if (userFromDB.Password == userModel.Password)
{
FormsAuthentication.SetAuthCookie(userFromDB.Username, checkBoxRememberMe.Checked);
//Use userFromDB as the username to authenticate because it will
//preserve capitalization of their username the way they entered it
//into the database; that way, if they registered as "Bob" but they
//type in "bob" in the login field, they will still be authenticated
//as "Bob" so their comments on your blogs will show their name
//the way they intended it to.
return "Successfully logged in!";
}
}
return "Invalid username or password.";
Now that they are authenticated you can just use Page.User.Identity.IsAuthenticated in your code to find out if they are logged in. LIke this:
if (User.Identity.IsAuthenticated)
{
DataLayer.PostBlogComment(User.Identity.Name, commentBody);
//Then in your controller that renders blog comments you would obviously
//have some logic to get the user from storage by the username, then pull
//their avatar and any other useful information to display along side the
//blog comment. This is just an example.
}
In addition, you can lock out entire action methods or even whole controllers to users that are authenticated through the forms authentication provider. All you have to do is add tags like these to your action methods/controllers:
[Authorize]
public ActionResult SomeActionMethod()
{
return View();
}
The [Authorize] attribute will prevent users that are not logged in from accessing that action method and it will redirect them to your login page. You can use this same attribute to filter out roles if you are using the built in roles provider.
[Authorize(Roles="Admin, SalesReps")]
public ActionResult SomeActionMethod()
{
return View();
}
These attributes can also be added above the controller class to apply it's logic to the entire controller.
EDIT: To log a user out all you need to do is call FormsAuthentication.SignOut();
Hey #Bibo, good for not choosing the Membership providers. I think a UserService or similar which provides methods for creating, authenticating users and some few more methods should be enough. As a suggestion, use password hashing and a password salt for the user´s password. Here is a good link to look at. Also have a look at this answer I gave some time ago.
Good luck!
EDIT: The rememberMe parameter should be named keepMeSignedIn instead.
This article on forms authentication gives you loads of info for creating your own simple security system, especially the bit about FormsAuthenticationTicket.
http://support.microsoft.com/kb/301240

Resources