Can't get User.Identity.GetUserId() - c#

I've got a simple web application and I can't user User.Identity.GetUserId() method. Every time I use it, it returns back null, or 0 if I use User.Identity.GetUserId<int>().
For example in this code part.
public async Task<ActionResult> SetPassword(SetPasswordViewModel model)
{
var userId = User.Identity.GetUserId();
if (ModelState.IsValid)
{
var result = await UserManager.AddPasswordAsync(User.Identity.GetUserId(), model.NewPassword);
if (result.Succeeded)
{
var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
if (user != null)
{
await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
}
return RedirectToAction("Index", new { Message = ManageMessageId.SetPasswordSuccess });
}
AddErrors(result);
}
Please , someone help me with this problem. Thanks again.

Related

External Login with Google Authentication

I am using Asp.net core for develop web application with google Authentication Login
I succeed to manage up to get google credential and register the User at very first. But the problems is even user register to the Application with Google Credentials,it always ask for register again and again for the application.
I found that it happen due to ExternalLoginSignInAsync function calling and it always give false for that ,I changed these parameters and tried several times
isPersistent:false/true) and bypassTwoFactor : true/false I have test above all variations. But it always give false for result .As well as I tried with Google Authentication with Normally Registered User login.it also gave me same result
public async Task<IActionResult> OnGetCallbackAsync(string returnUrl =null,string remoteError = null)
{
returnUrl = returnUrl ?? Url.Content("~/");
if (remoteError != null)
{
ErrorMessage = $"Error from external provider:
{remoteError}";
return RedirectToPage("./Login", new {ReturnUrl = returnUrl });
}
var info = await _signInManager.GetExternalLoginInfoAsync();
if (info == null)
{
ErrorMessage = "Error loading external login information.";
return RedirectToPage("./Login", new { ReturnUrl = returnUrl });
}
var result = await
_signInManager.ExternalLoginSignInAsync(info.LoginProvider,
info.ProviderKey, isPersistent:false, bypassTwoFactor : true);
if (result.Succeeded)
{
_logger.LogInformation("{Name} logged in with {LoginProvider}
provider.", info.Principal.Identity.Name,
info.LoginProvider);
// return LocalRedirect(returnUrl);
return LocalRedirect("/Customer/ProjectsApiKey/");
}
Could you please any anyone who has already resolved this this problems help me to.I am expecting what should I do for check user already registered or not with Google Authentication
When GetExternalLoginInfoAsync returns false you can check user exists, if the user exists then add login.
Otherwise, the user does not have an account, then asks the user to create an account.
var result = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false, bypassTwoFactor: true);
if (result.Succeeded)
{
return RedirectToAction("Index", "Home");
}
if (result.IsLockedOut)
{
return RedirectToAction(nameof(Lockout));
}
else
{
var user = await _userManager.FindByEmailAsync(email);
if (user != null)
{
var resultTemp = await _userManager.AddLoginAsync(user, info);
if (resultTemp.Succeeded)
{
await _signInManager.SignInAsync(user, isPersistent: true);
return RedirectToAction("Index", "Home");
}
}
// User does not have an account, then ask the user to create an account.
ViewData["ReturnUrl"] = returnUrl;
ViewData["LoginProvider"] = info.LoginProvider;
var email = info.Principal.FindFirstValue(ClaimTypes.Email);
return View("ExternalLogin", new ExternalLoginViewModel { Email = email });
}
I found the fault finally , it happened due to Email Confirmation thing,In my startup.cs class I have added the
config.SignIn.RequireConfirmedEmail = true;
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<IdentityUser>(config =>
{
config.SignIn.RequireConfirmedEmail = true;
})
.AddDefaultUI(UIFramework.Bootstrap4)
.AddEntityFrameworkStores<ApplicationDbContext>();
// requires
// using Microsoft.AspNetCore.Identity.UI.Services;
// using WebPWrecover.Services;
services.AddTransient<IEmailSender, EmailSender>();
services.Configure<AuthMessageSenderOptions>(Configuration);
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
due to this it always required to confirm the user Login email even we use Google Authentication.In order to fix this what I have did was when I create new user using Google Authentication login I set user parameters including EmailConfirmation=true addition to User name & User Email.Then that bug was fixed. after that when I call below function
var result = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false, bypassTwoFactor: true);
public async Task<IActionResult> OnPostConfirmationAsync(string returnUrl = null)
{
returnUrl = returnUrl ?? Url.Content("~/");
// Get the information about the user from the external login provider
var info = await _signInManager.GetExternalLoginInfoAsync();
if (info == null)
{
ErrorMessage = "Error loading external login information during confirmation.";
return RedirectToPage("./Login", new { ReturnUrl = returnUrl });
}
if (ModelState.IsValid)
{
// var user = new IdentityUser { UserName = Input.Email, Email = Input.Email }; comment dulith
var user = new ApplicationUser { UserName = Input.Email, Email = Input.Email ,EmailConfirmed=true};
var result = await _userManager.CreateAsync(user);
await _userManager.AddToRoleAsync(user, SD.User);
if (result.Succeeded)
{
result = await _userManager.AddLoginAsync(user, info);
if (result.Succeeded)
{
await _signInManager.SignInAsync(user, isPersistent: false);
_logger.LogInformation("User created an account using {Name} provider.", info.LoginProvider);
// return LocalRedirect(returnUrl);
return LocalRedirect("/Customer/ProjectsApiKey/");
}
}
If user Exists
result.Succeeded is true
And also Thank you very much for previous answer.

ResetPasswordAsync returns success but does not change the password

I have the following code to reset the password of a user (who actually does not have a password):
ApplicationUser u1 = _userManager.FindByEmailAsync("aclowneyb8#un.org").Result;
string resetToken1 = _userManager.GeneratePasswordResetTokenAsync(u1).Result;
IdentityResult r1 = _userManager.ResetPasswordAsync(u1, resetToken1, "12345Da*").Result;
r1 returns succeed but the password is indeed not changed. I cannot login with the new password. Any suggestions? What I am missing?
You should use async and await in this case to execute your code
Below is my example
[HttpPost("ResetPassword"), ValidModel, AllowAnonymous]
public async Task<IActionResult> ResetPassword([FromBody]ResetPasswordViewModel model)
{
if (string.IsNullOrEmpty(model.Token) || string.IsNullOrEmpty(model.Email))
{
return RedirectToAction("Index", "Error", new { statusCode = AppStatusCode.NotFound });
}
var isResetTokenValid = await _userManager.CheckValidResetPasswordToken(model.Token, model.Email);
if (!isResetTokenValid || string.IsNullOrEmpty(model.Email))
{
return StatusCode(AppStatusCode.ResetPassTokenExpire);
}
var user = await _userManager.FindByEmailAsync(model.Email);
if (user == null)
{
return Ok();
}
await _userManager.ResetPasswordAsync(user, model.Token, model.Password); // use await here
return Ok();
}

Core 2 Identity - Regenerate EmailConfirmationLink

I have a fairly standard implementation of Identity in my Core 2 application.
I have enabled the requirement for a confirmation email. This all works well - it generates and sends the email, with a valid link, which when clicks confirms the user's account. No problems there.
The situation is though, that if an email goes missing/is deleted/never arrives for whatever reason.
What I am doing, is using the standard login method, and if IsNotAllowed then I push them towards a page which tells them they need to activate their account, check their email etc.
On that page, I have a Form with a button which Posts to a controller to regenerate and resend the email.
I literally copy and pasted the code from the standard Register method into my custom method.
The problem is when clicking the link the Activation fails. I get an InvalidToken error.
Any ideas why and how to fix?
Login Method
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
{
ViewData["ReturnUrl"] = returnUrl;
if (ModelState.IsValid)
{
// This doesn't count login failures towards account lockout
// To enable password failures to trigger account lockout, set lockoutOnFailure: true
var result = await _signInManager.PasswordSignInAsync(model.Email,
model.Password, model.RememberMe, lockoutOnFailure : false);
if (result.IsNotAllowed)
{
var user = await _userManager.FindByEmailAsync(model.Email);
EmailConfirmationViewModel viewModel = new EmailConfirmationViewModel();
viewModel.Email = model.Email;
return RedirectToAction("AwaitingEmailConfirmation", viewModel);
}
if (result.Succeeded)
{
_logger.LogInformation("User logged in.");
return RedirectToAction("Index", "Races");
}
if (result.RequiresTwoFactor)
{
return RedirectToAction(nameof(LoginWith2fa), new { returnUrl, model.RememberMe });
}
if (result.IsLockedOut)
{
_logger.LogWarning("User account locked out.");
return RedirectToAction(nameof(Lockout));
}
else
{
ModelState.AddModelError(string.Empty, "Invalid login attempt.");
return View(model);
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
Register Method
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Register(RegisterViewModel model, string returnUrl = null)
{
ViewData["ReturnUrl"] = returnUrl;
if (ModelState.IsValid)
{
var user = new ApplicationUser
{
UserName = model.Email,
Email = model.Email,
FirstName = model.FirstName,
LastName = model.LastName,
MobileNumber = model.MobileNumber,
Marketing = model.Marketing,
Newsletter = model.Newsletter,
Source = "Website"
};
var result = await _userManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
_logger.LogInformation("User created a new account with password.");
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
var callbackUrl = Url.EmailConfirmationLink(user.Id, code, Request.Scheme);
await _emailSender.SendEmailConfirmationAsync(model.Email, callbackUrl);
//await _createContact.CreateContactAsync(model.Email, model.FirstName,
//model.LastName, model.Marketing, model.Newsletter);
var fields = new Dictionary<string, string>();
fields.Add("firstname", model.FirstName);
fields.Add("lastname", model.LastName);
fields.Add("newsletter", model.Newsletter.ToString());
fields.Add("marketing", model.Marketing.ToString());
fields.Add("source", "Website");
string publicaccountid = "55ebcc8b-b23f-4843-9dcb-1df08811de65";
var createcontact = ElasticEmailClient.Api.Contact.AddAsync(publicAccountID: publicaccountid,
email : model.Email, field : fields, sendActivation : false);
//await _signInManager.SignInAsync(user, isPersistent: false);
_logger.LogInformation("User created a new account with password.");
EmailConfirmationViewModel viewModel = new EmailConfirmationViewModel();
viewModel.Email = user.Email;
return RedirectToAction("AwaitingEmailConfirmation", viewModel);
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}
Resend Email Method
[HttpPost]
[AllowAnonymous]
public async Task<IActionResult> ResendConfirmationEmail(EmailConfirmationViewModel model)
{
var user = await _userManager.FindByEmailAsync(model.Email);
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
var callbackUrl = Url.EmailConfirmationLink(user.Id, code, Request.Scheme);
await _emailSender.SendEmailConfirmationAsync(model.Email, callbackUrl);
return RedirectToAction("AwaitingEmailConfirmation", model);
}

ExternalLoginConfirmation returns null after facebook successful login

Implementing Facebook login in MVC 5 template, had added the app Id and secret code.
Initially login was failing as it was returning null
public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
{
// Crashes on this line
var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
if (loginInfo == null)
{
return RedirectToAction("Login");
}
}
After searching came across a solution which says to replace existing ExternalLoginCallback method with this
[AllowAnonymous]
public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
{
var result = await AuthenticationManager.AuthenticateAsync(DefaultAuthenticationTypes.ExternalCookie);
if (result == null || result.Identity == null)
{
return RedirectToAction("Login");
}
var idClaim = result.Identity.FindFirst(ClaimTypes.NameIdentifier);
if (idClaim == null)
{
return RedirectToAction("Login");
}
var login = new UserLoginInfo(idClaim.Issuer, idClaim.Value);
var name = result.Identity.Name == null ? "" : result.Identity.Name.Replace(" ", "");
// Sign in the user with this external login provider if the user already has a login
var user = await UserManager.FindAsync(login);
if (user != null)
{
await SignInAsync(user, isPersistent: false);
return RedirectToLocal(returnUrl);
}
else
{
// If the user does not have an account, then prompt the user to create an account
ViewBag.ReturnUrl = returnUrl;
ViewBag.LoginProvider = login.LoginProvider;
return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { UserName = name });
}
}
Now that issue is solved but when I try to Associate your Facebook account.
You've successfully authenticated with Facebook. Please enter a user name for this site below and click the Register button to finish logging in.
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> ExternalLoginConfirmation(ExternalLoginConfirmationViewModel model, string returnUrl)
{
if (User.Identity.IsAuthenticated)
{
return RedirectToAction("Manage");
}
if (ModelState.IsValid)
{
// Here comes the error System.NullReferenceException: Object reference not set to an instance of an object.
var info = await AuthenticationManager.GetExternalLoginInfoAsync();
if (info == null)
{
return View("ExternalLoginFailure");
}
var user = new ApplicationUser() { UserName = model.UserName };
var result = await UserManager.CreateAsync(user);
if (result.Succeeded)
{
result = await UserManager.AddLoginAsync(user.Id, info.Login);
if (result.Succeeded)
{
await SignInAsync(user, isPersistent: false);
return RedirectToLocal(returnUrl);
}
}
AddErrors(result);
}
ViewBag.ReturnUrl = returnUrl;
return View(model);
}
On debugging the username come then too can't figure it out that why its throwing exception.
I think when it gets to GetExternalLoginInfoSync that returns null.
I had the same problem and here is how I managed to fix it and get the email from Facebook.
Update following NuGet Pacakges
Microsoft.Owin to version 3.1.0-rc1
Microsoft.Owin.Security to version 3.1.0-rc1
Microsoft.Owin.Security.Cookies to version 3.1.0-rc1
Microsoft.Owin.Security.OAuth to version 3.1.0-rc1
Microsoft.Owin.Security.Facebook to version 3.1.0-rc1
Then add the following code to the Identity Startup class
var facebookOptions = new FacebookAuthenticationOptions()
{
AppId = "your app id",
AppSecret = "your app secret",
BackchannelHttpHandler = new FacebookBackChannelHandler(),
UserInformationEndpoint = "https://graph.facebook.com/v2.8/me?fields=id,name,email,first_name,last_name",
Scope = { "email" }
};
app.UseFacebookAuthentication(facebookOptions);
This is the definition class for FacebookBackChannelHandler():
using System;
using System.Net.Http;
public class FacebookBackChannelHandler : HttpClientHandler
{
protected override async System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
System.Threading.CancellationToken cancellationToken)
{
// Replace the RequestUri so it's not malformed
if (!request.RequestUri.AbsolutePath.Contains("/oauth"))
{
request.RequestUri = new Uri(request.RequestUri.AbsoluteUri.Replace("?access_token", "&access_token"));
}
return await base.SendAsync(request, cancellationToken);
}
}
just update
Microsoft.Owin.Security.Facebook 3.0.1 to
Microsoft.Owin.Security.Facebook 3.1.0
worked for me.. but small issue you will not get email on next page after successfull login. that was fine for me.
Might be it can help some one:
var option = new Microsoft.Owin.Security.Facebook.FacebookAuthenticationOptions();
option.AppId = ConfigurationManager.AppSettings.Get("fbAppId");
option.AppSecret = ConfigurationManager.AppSettings.Get("fbAppSecret");
option.Scope.Add("email");
option.UserInformationEndpoint = "https://graph.facebook.com/v2.4/me?fields=name,email";
app.UseFacebookAuthentication(option);
I am getting everything, Name as well as Email
You have to update facebook version, you can use this code
Install-Package Microsoft.Owin.Security.Facebook -Version 3.1.0-rc1

Changing User Name breaks ASP.NET Identity

I have the following I use to change the UserName
// POST: /Manage/ChangeUserName
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> ChangeUserName(ChangeUserNameViewModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
var user = UserManager.FindById(User.Identity.GetUserId());
user.UserName = model.NewUserName;
var result = await UserManager.UpdateAsync(user);
if (result.Succeeded)
{
return RedirectToAction("Index", new { Message = ManageMessageId.ChangeUserNameSuccess });
}
AddErrors(result);
return View(model);
}
It successfully changes the name in the DB.
However once I log out. I can't log back in.
The user is still in the DB.
And the Login code
var result = await SignInManager.TwoFactorSignInAsync(model.Provider, model.Code, isPersistent: model.RememberMe, rememberBrowser: model.RememberBrowser);
Just returns SignInStatus.Failure
No other errors are occurring.
Any ideas why that is occurring?

Categories