I'm using SimpleMembership in an MVC4 app and need the ability for a user to change their own username.
I have the functionality working, so when a user changes their username it works. However when invoking things like Roles.IsUserInrole() then it fails as User.Identity.Name is set to what they logged in as, not the new value. That value no longer exists in the database, as they have changed their name.
I can't see a method to update the logged in user context with a username. For the most part I can store the users ID in session and retrieve it when doing queries, but I'm using the Roles method to display data in a view which fails.
Any ideas?
Thanks!
This is my current (working) solution:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(AccountEditModel model)
{
if (ModelState.IsValid)
{
if (HasSensitiveInformationChanged(model)) // model.EmailAddress.ToLower() != User.Identity.Name.ToLower()
{
if (Membership.ValidateUser(User.Identity.Name, model.Password)) // && WebSecurity.IsCurrentUser(User.Identity.Name)) //redundant?
{
using (UsersContext db = new UsersContext())
{
UserProfile user = db.UserProfiles.FirstOrDefault(u => u.EmailAddress.ToLower() == User.Identity.Name.ToLower());
if (user != null)
{
user.EmailAddress = model.EmailAddress;
db.SaveChanges();
WebSecurity.Logout();
WebSecurity.Login(model.EmailAddress, model.Password);
return RedirectToAction("Index", "Search");
}
else
{
ModelState.AddModelError("", "Could not find user. Please try logging in again.");
}
}
}
else
{
ModelState.AddModelError("","Could not change email address. Please verify your password and try again.");
}
}
else
{
//no change
return RedirectToAction("Index", "Search");
}
}
return View("Index", model);
}
I didn't think you were able to change the username field (would be nice if you could show me how you achieved that).
The only solution I see is that you force the user to log off after changing the username, so when they log back in they will have the correct User.Identity.Name.
Related
the idea is to create session and store it as a row in the database upon login, the session is created and get an id every time a login occurs, however updating the session with the user information does not work for now. I might be missing some tiny detail. I'm new to MVC in general and never implemented session befor, I took over this application and need to work further on it.
Code of the login page is strait forward nothing fancy other than there are two login ActionResults [Get] and [Post] one for creating the session(working) and the other suppose to update the session with the status and user information (not working!). Controller code looks like below:
[HttpGet]
public ActionResult Login()
{
SessionAid aid = new SessionAid();
var mysession = aid.CreateSession();
if (mysession.SessionID != 0)
{
Session["mySessionId"] = mysession.SessionID;
return View();
}
else
{
return Redirect("~/error");
}
}
[HttpPost]
public ActionResult Login(Login model)
{
string username = model.username;
string password = model.password;
if (ModelState.IsValid)
{
var session= new SessionData();
Session["SessionUserID"] = model.username;
Session["LastActiveTime"] = DateTime.UtcNow;
Session["CookiesId"] = sessionData.CookieID;
if (username == "name" && password == "password")
{
return RedirectToAction("Index", "Home");
}
return View();
}
then there is the session controller where the update Session table with userId and cookieId method is implemented
public ActionResult SaveSession(SaveRequest saveRequest)
{
var respon = new SessionResponse();
response.Session = new SessionData
{
SessionID = updatedSession.SessionID,
CookieID = updatedSession.CookieID,
SessionUserID = updatedSession.SessionUserID,
};
response.Success = true;
}
return response;
}
My question is how do I read the sessionId that is created in [HTTPGet] login method in the [HttpPost] login method, so I can update the session row in the database with cookieId and userID? What am I missing?
from what I understand, you can use the Session object you are storing the SessionID at.
ex:
int SessionId = Session["mySessionId"] as int;
this way you can get any thing you've stored in the Session object anywhere you want.
I have a .NET MVC5 website, where the user is logged in using Microsoft Identity. I have multiple form posts for adding and editing items across the site. I'm looking to know which order I should perform validation in:-
ModelState.IsValid and then User.Identity.IsAuthenticated
User.Identity.IsAuthenticated then ModelState.IsValid
I currently have the following code which works, but it seem to be a case of 'the chicken and egg':-
var user = UserAccountFunctions.GetUser(User);
if (user != null)
{
ClientProfile profile = ClientProfile.GetUser(user.Id, db);
if (profile != null)
{
if (ModelState.IsValid)
{
// Do logic here
}
}
}
Should I swap this code round to check the model first, before checking authentication so that I have:-
if (ModelState.IsValid)
{
var user = UserAccountFunctions.GetUser(User);
if (user != null)
{
ClientProfile profile = ClientProfile.GetUser(user.Id, db);
if (profile != null)
{
// Do logic here...
}
}
}
Or is there simply no difference here? I repeat this code a lot throughout the site, so looking for which is the better option? I currently use the top one, because I feel that you shouldn't even attempt to check the model unless they are authenticated?
Any advice here?
Thanks!
Here is example of updating users's email:
[AcceptVerbs(HttpVerbs.Post)]
[Authorize]
[ValidateAntiForgeryToken()]
public ActionResult emailupdate(UserEmailEditModel editmodel_post)
{
if (!ModelState.IsValid)
{
// redirect to email view and show errors
}
// check if posted id is the same as stored in session
if (User.Identity.GetUserId() != editmodel_post.user_id.ToString())
{
// redirect to email view and show errors
}
}
So
Use Authorize attribute
Use ValidateAntiForgeryToken attribute
Check ModelState
Check against session or database
I'm working on ASP.NET MVC5 app based around Parse.com framework.
Since i can't use Parse login method i had to use method posted here to work around its limitations: Parse.com multiple users issue
Here is my login method(just minor changes):
public async Task<ActionResult> Login(AccountModel model) //no returnUrl string
{
ParseUser user;
try
{
user = await ParseUser.LogInAsync(model.UserName, model.Password);//login parse user
}
catch (Exception e)
{
ModelState.AddModelError("", "The user name or password provided is incorrect.");
return View(model);
}
//making setAuthCookie get parse object id instead of username
FormsAuthentication.SetAuthCookie(user.ObjectId, model.RememberMe);
ParseUser.LogOut(); //log out parse user
return RedirectToAction("index", "home"); //Redirect to Action
}
So basically i (parse)login user, set AuthCookie to it's object id and then (parse)logoff user. That way i can have multiple users logged in.Out of SetAuthCookie i can get users id now.
However i'd like to display some extra user data(like user adress, Type, Name, LastName) that is on parse.com cloud. So i figured i will just write a method that will get this data by using currently authenticated userID, fill my AccountModel class object with data and then pass it to views. This is a loose idea of how it'd look like(i know syntax is probably wrong, i don't have access to my Visual studio right now):
UserData model:
public async Task<AccountModel> GetUserData()
{
AccountModel userData = new AccountModel();
ParseObject user;
ParseQuery<ParseObject> query = ParseObject.GetQuery("_User");
try
{
//i can't remember how to get authenticated user identity
user = await query.GetAsync(AuthenticatedUser.Identity());
}
catch(Exception e)
{
//code to handle exception
}
userData.Name = user.Get<string>("Name");
userData.Lastname = user.Get<string>("Lastname");
userData.Adress = user.Get<string>("Adress");
return userData; //it will probably throw an error
}
Controller:
public ActionResult Index()
{
UserData model = new UserData();
return View(model.GetUserData());
}
So now it will probably throw an error(can't return T from Task< T >) and i have no idea how to fix this, so i can get currently logged in user data.
I have nav bar on my site where user name and last name is displayed, so i have to somehow get currently logged in user data every time page is displayed. Is there any work around/easier way to achieve this?
You fix this by making your Action asynchronous as well:
public async Task<ActionResult> Index()
{
UserData model = new UserData();
return View(await model.GetUserData());
}
Async goes "all the way". This means that once you have an asynchronous method that needs to be awaited, it will usually cause most (if not all) of your stack-trace to be asynchronous as well.
Side note:
Once should stick to .NET conventions and mark async methods with the XXXAsync postfix, so your method should actually be named GetUserDataAsync.
I have started learning C# MVC 5 for a Room Inventory project i am working on where i work.
I am using active directory to authenticate users and then store these details in a database so that i can then assign users to rooms and tenancies that have items assigned to them.
I used the stock MVC 5 template that comes with Visual Studio 2013 as i only have a month to do the project coming in to it with no previous knowledge and dont have the time to code a fancy looking html / css front end and am relying on the look that comes out of the box.
I have written some code that once a user successfully logged on using form authentication linked with AD it runs a check to see if a user exists in the database, if not it creates one, if it does, it checks to see if it has been set to inactive and reactivates it if needed.
I have placed this code in the AccountController under the login httppost action. As i am new to MVC i wanted to check to see if this is the correct position, or if i should create a new class for this functionality, or if it should be in the model area where i create the database using entity framework code first. What is the best practice?
Here is the code and thanks in advance for any help. I apologize for the long winded post and less than stellar code. Dont hold back with any criticism as i would rather get it right now than make mistakes again and again.
[HttpPost]
public ActionResult Login(LoginModel model, string returnUrl)
{
if (!ModelState.IsValid)
{
return View(model);
}
// Put this method in place to allow multiple domains for login. References Web.config for providers
MembershipProvider domainProvider;
switch (model.Domain)
{
case "Student":
domainProvider = Membership.Providers["studentADMembershipProvider"];
break;
case "Staff":
domainProvider = Membership.Providers["staffADMembershipProvider"];
break;
default:
throw (new Exception("This domain is not supported"));
}
// Method for authenticating users on AD to allow system integration and also add or update user in Users Database
if (domainProvider.ValidateUser(model.UserName, model.Password))
{
FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
//Code for creating new user based on successfull logged in user.
//define which domain to link too. otherwise will always default to staff
PrincipalContext myContext;
if (model.Domain == "Staff")
{
myContext = new PrincipalContext(ContextType.Domain, "staff.domain.com");
}
else
{
myContext = new PrincipalContext(ContextType.Domain, "student.domain.com");
}
UserPrincipal aduser = UserPrincipal.FindByIdentity(myContext, IdentityType.SamAccountName, model.UserName);
//Check for existence of user with username that matches loged in user
var userSearch = db.Users.Count(b => b.Username == aduser.SamAccountName);
if (userSearch == 0)
{
// User does not exist, therefore create user
User user = new User()
{
IsActive = 1,
Username = aduser.SamAccountName,
FirstName = aduser.GivenName,
LastName = aduser.Surname,
Extension = aduser.VoiceTelephoneNumber,
Email = aduser.EmailAddress,
UserTypeId = 3
};
db.Users.Add(user);
db.SaveChanges();
}
else
{
// User does exist, but has been deactivated, therefore reactivate
var activateUser = db.Users.FirstOrDefault(d => d.Username == aduser.SamAccountName);
if (activateUser.IsActive == 0)
{
activateUser.IsActive = 1;
db.SaveChanges();
//db.Users(activateUser.UserId).State = EntityState.Modified;
}
}
if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/")
&& !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\"))
{
return Redirect(returnUrl);
}
return RedirectToAction("Index", "Home");
}
ModelState.AddModelError(string.Empty, "The user name or password provided is incorrect.");
return View(model);
}
The goal
Get the user information after successful authentication.
The problem
Take a look in the following fragment of code:
[AcceptVerbs(HttpVerbs.Post)]
[ValidateAntiForgeryToken]
[AllowAnonymous]
public ActionResult Authenticate(User userModel)
{
if (ModelState.IsValid)
{
if (userModel.IsValid(userModel.Email, userModel.Password))
{
FormsAuthentication
.SetAuthCookie(userModel.Email, userModel.Remember);
return RedirectToAction("Index", "Manager");
}
else
{
ModelState.AddModelError("", "Login data is incorrect!");
}
}
return RedirectToAction("Index");
}
As you can see, it is a normal authentication's controller. What I need is simple: if the statement userModel.IsValid is true, how can I get the user information based on the email that he sent to the server by userModel.Email?
Maybe store the email on the session and in the Index method call some method to get the (user) information passing through parameter the email that inhabiting the session? (I think this isn't the best way because if the cookie exist and the session not, there will be a problem here.)
Code spotlight
To get information of some user, I'm using a simple method: User.Invoke((string) userEmail).
Knowledge improvement
I'm logging in on my website with email and password as various applications of the world do. With the email that the user enters, I'm attempting to get his information from database. So I ask: is this the best way to do this? Maybe isn't better firstly get the ID of the user by his email and then select his information?
What I already tried
In the Authenticate method (the same that I passed before), I implemented the following code:
[...]
public ActionResult Authenticate(User userModel)
[...]
if (userModel.IsValid(userModel, userModel.Password))
{
FormsAuthentication
.SetAuthCookie(userModel.Email, userModel.Remember);
Session["UserEmail"] = userModel.Email; // <-- Pay attention to this
return RedirectToAction("Index", "Manager");
}
[...]
}
And then, in the Index method:
public ActionResult Index()
{
if(Request.IsAuthenticated())
{
UserProfile user = User.Invoke(Session["UserEmail"]));
return View(user);
}
else
{
return View();
}
}
But as I said, if the cookie that flags that the user is logged in is alive and the session not, there will be a problem right here — a kind of concept conflict (cookie vs. session).
What can I do?
The accepted answer (from the discussion with the OP) is : the most straightforward way of retrieving the user name set by the forms authentication module is to use
HttpContext.Current.User.Identity.Name
or just
this.User.Identity.Name
in a controller.