The name "'_emailSender'" does not exist in the current context - authentication

I'm trying to learn authentication on razor pages
https://learn.microsoft.com/en-us/aspnet/core/security/authentication/identity?view=aspnetcore-5.0&tabs=visual-studio
And when I changed the Login page as they wrote in the example-
public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
returnUrl = returnUrl ?? Url.Content("~/");
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync())
.ToList();
if (ModelState.IsValid)
{
var user = new IdentityUser { UserName = Input.Email, Email = Input.Email };
var result = await _userManager.CreateAsync(user, Input.Password);
if (result.Succeeded)
{
_logger.LogInformation("User created a new account with password.");
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
var callbackUrl = Url.Page(
"/Account/ConfirmEmail",
pageHandler: null,
values: new { area = "Identity", userId = user.Id, code = code },
protocol: Request.Scheme);
await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",
$"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
if (_userManager.Options.SignIn.RequireConfirmedAccount)
{
return RedirectToPage("RegisterConfirmation",
new { email = Input.Email });
}
else
{
await _signInManager.SignInAsync(user, isPersistent: false);
return LocalRedirect(returnUrl);
}
}
foreach (var error in result.Errors)
{
ModelState.AddModelError(string.Empty, error.Description);
}
}
// If we got this far, something failed, redisplay form
return Page();
}
I get the error-
The name "'_emailSender'" does not exist in the current context
And I searched later if there is a reference to the _emailSender class and did not see. Does anyone know how to fix this error?
Best regards

I should have added -
private readonly IEmailSender _emailSender;
Too bad they did not write it, it would have saved me a lot of time

Related

How to return a cookie from an ASP.NET Core Auth Cookie in a Controller

I currently have a razor page where I return a cookie and it works great. However, I am developing a SPA which uses VueJS so I have created an API to directly communicate with. I have converted my code from the Razor Page to the controller but I am not sure how I actually return the cookie when the user tries to log in. If there is a match I want it to return the cookie and create the cookie. As of now I get a 400 code as if this request is not working. Any thoughts what could be wrong with this?
public class LoginController : Controller
{
private readonly LoginDBContext _context;
private string connectionString;
public IConfiguration Configuration { get; }
public LoginController(LoginDBContext context, IConfiguration configuration)
{
_context = context;
connectionString = configuration["ConnectionStrings:MMCARMSContext"];
}
// GET: HomeController
public ActionResult Index()
{
return Ok(new { Result = "Test" });
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login([FromForm] string Username, [FromForm] string Password, [FromForm] bool RememberMe)
{
if (!String.IsNullOrEmpty(Username) && !String.IsNullOrEmpty(Password))
{
var users = _context.UsersAccountsTbl
.Where(a => a.Username == Username)
.Select(a => new { a.InternalUserNumber, a.Username, a.Password })
.ToArray();
if (users.Length == 1) //if we have more than 1 result we have security issue so do not allow login
{
var passwordHasher = new PasswordHasher<string>();
//To use you need to has with var hashedPassword = passwordHasher.HashPassword(UserName, Password);
//System.Diagnostics.Debug.WriteLine(passwordHasher.HashPassword("Username", "password"));
var user = users.First();
if (passwordHasher.VerifyHashedPassword(user.Username, user.Password, Password) == PasswordVerificationResult.Success)
{
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, user.InternalUserNumber.ToString())
};
var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
if (RememberMe)
{
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme,
new ClaimsPrincipal(claimsIdentity),
new AuthenticationProperties
{
IsPersistent = RememberMe,
ExpiresUtc = DateTimeOffset.UtcNow.AddHours(2)
});
}
else
{
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme,
new ClaimsPrincipal(claimsIdentity));
}
return Ok(new { Result = "Cookie has been created!" });
}
else
{
return Ok(new { Result = "Password is incorrect!" });
}
}
return Ok(new { Result = "Username or Password does not exist!" });
}
else
{
return Ok(new { Result = "Username or Password invalid!" });
}
}
}
You could set the cookie in the HttpResponse, this way the cookie gets added when the client receives the response from your controller:
HttpCookie MyCookie = new HttpCookie("LastVisit");
DateTime now = DateTime.Now;
MyCookie.Value = now.ToString();
MyCookie.Expires = now.AddHours(1);
Response.Cookies.Add(MyCookie);
https://learn.microsoft.com/en-us/dotnet/api/system.web.httpresponse.cookies?view=netframework-4.8

Asp.net Core Object reference not set to an instance of an object

ASP.NET CORE API
The logged in user gives an error in the code below while adding a photo. Can anybody help?
var currentUserId = int.Parse(User.FindFirst(ClaimTypes.NameIdentifier).Value)
This code gives an error. Help me
Object reference not set to an instance of an object
PhotosController.cs
[HttpPost]
public ActionResult AddPhotoForCity(int cityId,[FromForm]PhotoForCreationDto photoForCreationDto)
{
var city = _appRepository.GetCityById(cityId);
if (city == null)
{
return BadRequest("Could not find the city.");
}
var currentUserId = int.Parse(User.FindFirst(ClaimTypes.NameIdentifier).Value);
karşılaştırmak gibi
if (currentUserId != city.UserId)
{
return Unauthorized();
}
var file = photoForCreationDto.File;
var uploadResult = new ImageUploadResult();
if (file.Length > 0)
{
using (var steam = file.OpenReadStream())
{
var uploadParams = new ImageUploadParams()
{
File = new FileDescription(file.Name,steam)
};
uploadResult = _cloudinary.Upload(uploadParams);
}
}
photoForCreationDto.Url = uploadResult.Url.ToString();
photoForCreationDto.PublicId = uploadResult.PublicId;
var photo = _mapper.Map<Photo>(photoForCreationDto);
photo.City = city;
if (!city.Photos.Any(p => p.IsMain))
{
photo.IsMain = true;
}
city.Photos.Add(photo);
if (_appRepository.SaveAll())
{
//eklenen fotoğrafı döndürüyoruz
var photoToRetun = _mapper.Map<Photo>(photoForCreationDto);
return CreatedAtRoute("GetPhoto", new {id = photo.Id}, photoToRetun);
}
return BadRequest("Cloud not add the photo");
}
AuthController.cs
[Route("api/[controller]")]
[ApiController]
public class AuthController : ControllerBase
{
private IAuthRepository _authRepository;
private IConfiguration _configuration;
public AuthController(IAuthRepository authRepository, IConfiguration configuration)
{
_authRepository = authRepository;
_configuration = configuration;
}
[HttpPost("register")]
public async Task<IActionResult> Register([FromBody] UserForRegisterDto userForRegisterDto)
{
if (await _authRepository.UserExists(userForRegisterDto.UserName))
{
ModelState.AddModelError("UserName", "Username already exists");
}
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var userToCreate = new User
{
UserName = userForRegisterDto.UserName
};
var createdUser = await _authRepository.Register(userToCreate, userForRegisterDto.Password);
return StatusCode(201);
}
[HttpPost("login")]
public async Task<ActionResult> Login([FromBody] UserForLoginDto userForLoginDto)
{
var user = await _authRepository.Login(userForLoginDto.UserName, userForLoginDto.Password);
if (user == null)
{
return Unauthorized();
}
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(_configuration.GetSection("AppSettings:Token").Value);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new Claim[]
{
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
new Claim(ClaimTypes.Name, user.UserName)
}),
Expires = DateTime.Now.AddDays(1),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key)
, SecurityAlgorithms.HmacSha512Signature)
};
var token = tokenHandler.CreateToken(tokenDescriptor);
var tokenString = tokenHandler.WriteToken(token);
return Ok(tokenString);
}
}
From the above code snippet you have shared, they mostly likely reason you are getting this error is because the user is not logged in, and hence this line of code
User.FindFirst(ClaimTypes.NameIdentifier).Value
is throwing an exception.
You could either do it like this.
User.FindFirst(ClaimTypes.NameIdentifier)?.Value
Or
[HttpPost]
[Authorize] // make sure you authorize your action method by adding this attribute and
// only allow logged in user to access it.
public ActionResult AddPhotoForCity(int cityId,[FromForm]PhotoForCreationDto photoForCreationDto)
{
}
try this one:
var currentUserId = int.Parse(User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier).Value);

ASP.NET Core - Registering new Users

I'm adding the functionality of adding new users to my project following this project:
http://www.c-sharpcorner.com/article/asp-net-core-mvc-authentication-and-role-based-authorization-with-asp-net-core/
However, I encounter a problem when I try to Add a new user:
On the Post Method of the UserController:
[HttpPost]
public async Task<IActionResult> AddUser(UserViewModel model)
{
if (ModelState.IsValid)
{
ApplicationUser user = new ApplicationUser
{
Name = model.Name,
UserName = model.UserName,
Email = model.Email
};
IdentityResult result = await userManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
ApplicationRole applicationRole = await roleManager.FindByIdAsync(model.ApplicationRoleId);
if (applicationRole != null)
{
IdentityResult roleResult = await userManager.AddToRoleAsync(user, applicationRole.Name);
if (roleResult.Succeeded)
{
return RedirectToAction("Index");
}
}
}
}
return View(model);
I'm getting an error on this line:
IdentityResult result = await userManager.CreateAsync(user, model.Password);
if (result.Succeeded)
When I put a break here, I see that result is null.
I'm trying to solve it on my own but no luck so far.
Any ideas? Thanks in advance for any help.
Regards,

User roles are zero after login in MVC6?

I am using the default site template that comes in visual studio 2015. I have added some roles and assigned roles to the user. When a used signs in, the roles are zero. What do I need to do to get the roles working?
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
{
if (ModelState.IsValid)
{
var signInStatus = await SignInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, shouldLockout: false);
switch (signInStatus)
{
case SignInStatus.Success:
var user = await GetCurrentUserAsync();
return RedirectToLocal(returnUrl);
case SignInStatus.Failure:
default:
ModelState.AddModelError("", "Invalid username or password.");
return View(model);
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
Looking at your code, it looks like you're missing any check for a role.
I was having this similar problem and after digging into the code I noticed that GetCurrentUserAsync() was not returning a valid user object and was intact returning a null object. Context.User.GetUserId() is the problem and isn't returning a user id to pass on to the UserManager.
Until this is resolved I'm using the following:
if (result.Succeeded)
{
var user = await UserManager.FindByEmailAsync(model.Email);
if (await UserManager.IsInRoleAsync(user, Roles.Admin))
{
return RedirectToAction("Index", "Admin");
}
return RedirectToLocal(returnUrl);
}
While this isn't ideal it does work
This works for me...does not redirect correct for Invalid username or password 4 me yet...will check...
public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
{
ViewBag.ReturnUrl = returnUrl;
if (ModelState.IsValid)
{
var result = await SignInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, shouldLockout: false);
if (result.Succeeded)
{
return RedirectToLocal(returnUrl);
}
if (result.RequiresTwoFactor)
{
return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
}
if (result.IsLockedOut)
{
return View("Lockout");
}
else
{
ModelState.AddModelError("", "Invalid username or password.");
return View(model);
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
this is for MVC 6, (VS 2015 RC)...u can find it all here : https://github.com/aspnet/Identity/tree/dev/samples/IdentitySample.Mvc

Claims Authentication ASP.NET vNext

When adding a claim to the user, the claims information does not get recorded as a cookie on the page and the information gets lost for all other requests. Why does this happen?
public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
{
if (ModelState.IsValid)
{
try
{
var authReq = new AuthenticationViewModel() { password = model.Password, username = model.UserName };
var userInfo = await _dataService.AuthenticateAsync(authReq);
var claims = new List<Claim>();
claims.Add(new Claim("username", userInfo.user.userName));
claims.Add(new Claim("AddtionalData", userInfo.AddtionalData));
var user = ClaimsPrincipal.Current;
var identity = user.Identities.Where(x => x.AuthenticationType == "Custom").FirstOrDefault();
if (identity == null)
identity = new ClaimsIdentity(claims.ToArray(), "Custom");
user.AddIdentity(identity);
return RedirectToAction("Users", "Index");
}
catch (Exception)
{
ModelState.AddModelError("", "Invalid username or password.");
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
I found the issue, I needed to add the following code:
context.Response.SignIn(new ClaimsIdentity(new[] { new Claim("name", "bob") }, CookieAuthenticationDefaults.AuthenticationType));
also, I changed the AuthenticationType to be CookieAuthenticationDefaults.AuthenticationType.
Please see link with Sample