Get name of currently logged in user [duplicate] - c#

This question already has answers here:
_userManager.GetUserAsync(User) returns null
(3 answers)
Closed 3 years ago.
I made a simple login using Identity. I logged in with signInManager.PasswordSignInAsync().
If the login was successful, I would like to get the currently logged in user's data using the userManager.
The problem is that I can only get an id from the GetUserAsync and don't know what to do with it.
var result = await mSignInManager.PasswordSignInAsync(username, password, true, false);
if (result.Succeeded)
{
//var loggedUser = mUserManager.GetUserName(HttpContext.User);
var userData = mUserManager.GetUserAsync(HttpContext.User);
var user = await mUserManager.FindByIdAsync(userData.Id.ToString());
return Redirect("/createpost");
}

To me it looks like you are logging the user in and immediately trying to access the user info. The httpContext has not had the chance to update and still reflects the time when there was no user logged in. Try moving your user info retrieval logic to "createpost" where it gets executed on the next http roundtrip.
public async Task<IActionResult> createpost()
{
var userData = await mUserManager.GetUserAsync(HttpContext.User);
Debug.WriteLine(userData.Id);
Debug.WriteLine(userData.UserName);
Debug.WriteLine(userData.Email);
return View();
}

You've got two issues. First, GetUserAsync relies on the principal being set in HttpContext, which hasn't occurred yet, so that method will fail. There must be an intervening request before you can access the user that way.
What you can do is pull the user out directly using something like FindByIdAsync, which you're attempting to do already. However, you're trying to find the user based on the id of the user instance you tried to retrieve via GetUserAsync. Since that failed, there will be no user, and thus no id to use in this lookup, causing it to fail as well. It doesn't even make sense to do this, as if you had the user already to get the id from, there'd be no point in looking that user up by its id.
So, what you need to do is look the user up by information you actually do have, which based on your code, is username. Therefore, do:
var user = await mUserManager.FindByNameAsync(username);

The reason is that the user will be available for next request, you could not get the user in this current request,let alone user's name.

Related

Okta 'request body was not well-formed' during very simple property update

I am calling the okta API from my .Net back-end. It works fine when creating the user (the first part of the snippet below), so I know the token is correct etc. and I can confirm the new user exists.
I also, subsequently, update a property I've added to the user called 'Site'. When attempting to assign this property a value it throws an exception on the 'UpdateAsync' line that the request body was not well formed
var user = await _oktaClient.Users.CreateUserAsync(new CreateUserWithPasswordOptions
{
Profile = new UserProfile
{
FirstName = value.FirstName,
LastName = value.Surname,
Email = value.Email,
Login = value.Email,
},
Password = value.Password,
Activate = true,
});
var newUser = await _oktaClient.Users.GetUserAsync(user.Id);
newUser["site"] = Site;
await newUser.UpdateAsync(); // This line throws!
Note: I wasn't always doing it this way, I was previously assigning to the user object and then calling UpdateAsync() once I'd updated 'site' on the user object. This is an alternative approach as I'm trying different things (i.e. getting the user from the API again). Neither approach works.
What's very strange is that this has been working, I am 100% certain of that. I'm looking through my okta users directory 'as we speak', and there are a load of users, all with their site property populated. There has been no problem previously. I believe something must've been updated okta's end that now doesn't like my request for some reason but in either case I need a work-around ideally.
I can confirm Site is neither null or empty, it's simply a string.
UPDATE
I just discovered a SetProperty extension on okta's IResource, calling this before attempting to update the user causes the same issue.
Any help on this greatly appreciated.
Looks like custom attributes can't be assigned to the User object itself anymore, but need to be in the users profile: newUser.Profile["site"] = Site;

Update object values that changed

I currently have a the following Situation:
There is a profile section in my application where users can update their profile data. Therefore I have a mvc form where users can add additional infos or modify their data. In my form submit function I am receiving a user object that is mostly filled out but not completely (some of the values are null because I am using identity service and i don't want the user to change the password hash for example).
Now here is my question:
How can I update my user object without writing something like this: (profileData.User is the submitted user)
var user = await _userManager.FindByIdAsync(profileData.User.Id);
user.Email = profileData.User.Email;
user.Salutation = profileData.User.Salutation;
user.FirstName = profileData.User.FirstName;
user.LastName = profileData.User.LastName;
...
var result = await _userManager.UpdateAsync(user);
I obviously cannot use this as this would override the all the fields that are not set in the submitted user:
var user = profileData.User
Is there a way to update my user object without overriding all the fields?
One of the good reasons for using DTOs is that you can have a different one for every get/update pair of functions. Rather than having one 'catch-all' update function, why not have one that will one update the properties you can change in each form. Yes, you will end up with lots of classes and functions, but you also get simple to test, single use functions that do one job well (and you don't get the sort of problems you are asking about).
var user = await _userManager.FindByIdAsync(profileData.User.Id);
user.Email = profileData.User.Email;
user.Salutation = profileData.User.Salutation;
user.FirstName = profileData.User.FirstName;
user.LastName = profileData.User.LastName;
var result = await _userManager.UpdateProfileAsync(user); <-- Only updates the 'profile' fields
I would also go some way to argue that FindByIdAsync should not be returning password/salt etc. Perhaps you should have a function FindProfileByIdAsync.

Get current user's name and user id

I dont do aspx at all so trying to work out this simple task.
I see the following code in some cs files which guess gets the current user and i assume this is a standard method in asp but might be wrong:
CS:
User user = (User)Context.Items["CurrentUser"];
I have tried things like this from other posts on here but maybe this system is different or the setup is different? again i dont know.
var currentUser = Membership.GetUser(User.Identity.Name);
string username = currentUser.UserName; //** get UserName
Guid userID = currentUser.ProviderUserKey; //** get user ID
Does anyone know how i can get the Name and User ID of the current user based on what is written above?
it depends on how you handle users in your website.
if you use the asp.net built in user management, then User.Identity.Name will get you the currently logged in username.
other stuff like (User)Context.Items["CurrentUser"] or (User)Session["myUser"] will get you the user which was saved in those places somewhere in your website.
you just need to start your way from the login page, and follow the functions to see how users are being handled in your website.

How to get UserId from a PasswordReset token in ASP.NET Identity 2.0?

To reset a password we need to know a UserId and pass it to the UserManager.ResetPasswordAsync method. In the Identity 1.0 it was possible to obtain UserId from the UserManager.PasswordResetTokens.Validate method ((UserManager.PasswordResetTokens.Validate(token)).UserId). Now it's gone and all existing examples telling me that I need to ask an user for username or email. This is not user friendly, I don't want my users enter username again if token is valid.
This is already established tradition in ASP.NET Identity - something that worked before is broken in the new release. Of course I can create my own combined token with embedded UserId, but why I need to do extra work? New releases should improve things, not make them worse.
Asp.Net Identity 2.x do not provide a way to find a user by a token created from GeneratePasswordResetTokenAsync method.
You have two options:
1) Add the user id at the url you will send to the user. Ex:
var token = await _userManager.GeneratePasswordResetTokenAsync(applicationUser);
var callbackUrl = $"/reset-password/?user={WebUtility.UrlEncode(applicationUser.Id)}&code={WebUtility.UrlEncode(token)}";
This approach is more user friendly. But I know people that says this is a security issue because anyone with the link could reset the user password.
2) Ask for the user name at the reset password page, as you did. Ex:
public async Task<YourResultModel> ResetPassword(ResetPasswordViewModel vm)
{
// Your password validations...
var user = await _userManager.FindByNameAsync(vm.UserName);
// could be FindByEmailAsync if your app uses the user e-mail to login.
IdentityResult result = await _userManager.ResetPasswordAsync(user, vm.Token, vm.NewPassword);
return YourResultModelFromIdentityResult(result);
}
Before choose between this two approaches you need to think about your specific scenario. For example: If your app uses the user e-mail as username and to intercept the token the "interceptor" needs to access the user e-mail box, remove the user id from reset password link will not improve the security of your app. Because who has the link already knows the e-mail of the user.

Verify newly entered password of logged in user

User is logged in and wants to do something major and I want them to re-enter their password so I can make sure that they are the user that is logged in.
How can I confirm that this password is for the account holder?
Would be happy to know how to do it via ASP.NET Identity or how to set up a stored proc to go against the AspNetUsers table or how to do it via Entity Framework.
How can I confirm that this password is for the account holder?
how to do it via ASP.NET Identity
To reverify the password of currently logged in user, provide the user VerifyView to enter password and use the following method to check if the user exists.
var user = await UserManager.FindAsync(User.Identity.Name,VerifyViewModel.Password)
If the user is found, the current request is the same from the account holder.
Membership.ValidateUser is from earlier version of Membership framework, not from ASP.NET Identity.
You can also use UserManager.CheckPassword() extension function:
UserManagerExtensions.CheckPassword Method
string id = User.Identity.GetUserId();
var user = UserManager.FindById(id);
if(!UserManager.CheckPassword(user, model.Password))
{
ModelState.AddModelError("Password", "Incorrect password.");
}
With Identity framework you never want to hit the database directly. Always use the API provided. The database structure has changed several times in the past few years, so introducing dependencies (e.g. on a data context) is adding work for no reason.
For async usage, see the answer already provided by jd4u.
For synchronously identifying that the password matches the current user, you need to first include:
using Microsoft.AspNet.Identity;
as this brings in a number of synchronous extension methods for identity framework.
You can then check with Find on the UserManager like this:
var user = UserManager.Find(User.Identity.Name, password);
if (user != null)
{
// It is them!
}
If the user is not null, then you have a match of password and current username.
You can use UserManager to do that:
if(UserManager.PasswordHasher.VerifyHashedPassword("hashedPassword", "password")
!= PasswordVerificationResult.Failed)
{
// password is correct
}
For more information see the link:
How to check password manually in Asp.Net identity 2?

Categories

Resources