The Challange method does not redirect to the specified url - asp.net-core

I'm making a site with external authorization through VK, I've looked through a lot of examples, but I ran into one problem, in all examples redirection to ExternalLoginCallback happens through Challange method with provider parameters and url, but redirection happens not to specified url, but to signin-vkontakte-token, which is specified in ConfigureServices. What can this be related to?(It doesn't matter if you give me an answer with the specified provider or another one, such as Facebook)
[AllowAnonymous]
public IActionResult ExternalLogin(string provider, string returnUrl)
{
var redirectUrl = Url.Action(nameof(ExternalLoginCallback), "Home", new { returnUrl });
var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl);
return Challenge(properties, provider);
}
[AllowAnonymous]
public async Task<IActionResult> ExternalLoginCallback(string returnUrl)
{
var info = await _signInManager.GetExternalLoginInfoAsync();
if (info == null)
{
return RedirectToAction("Index");
}
var result = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, false, false);
if (result.Succeeded)
{
return RedirectToAction("Index");
}
return RedirectToAction("Index");
}

Related

Redirect To Action Not Working after login ASP.NET Core Identity (.Net 5)

Even after a successful sign-in it does not redirect to action but stays on the login page.
I have put breakpoints but have not been able to know what exactly is wrong with my code.
Even if the condition is true the code is not executed.
Here is my code:
[HttpPost]
public async Task<ActionResult> Login(LoginViewModel model)
{
if (ModelState.IsValid)
{
var user = await _context.Users.SingleOrDefaultAsync(u => u.UserName == model.UserName);
if (user != null)
{
var result = await _signInManager.PasswordSignInAsync(user, model.Password, true, false);
if (result.Succeeded)
{
var role = await _userManager.GetRolesAsync(user);
if (role.Contains("Client"))
{
return RedirectToAction("Index", "MyDashboard");
}
if (role.Contains("Admin"))
{
return RedirectToAction("Index", "Admin");
}
}
}
else
{
ModelState.AddModelError("", "Invalid login attempt");
return View(model);
}
}
return View();
}
I got the solution myself. Actually, I was missing Authentication middleware in the startup class. After adding app.UseAuthentication() ,it works fine. Thanks.

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

Force 2 Factor Authentication for new users when they login for the first time .NET Core

I am trying to configure the 2FA when users log in for the first time in .net core. So I added an if condition for checking if 2FA is not enabled then redirecting to creating MFA, however, a major flaw here is that the users can change the URL link on the browser to skip 2FA creation, how can I avoid this? Below are my Account Controller Codes:
Login Controller Methods
[HttpGet]
[AllowAnonymous]
public IActionResult Login(string? returnurl = null)
{
ViewData["ReturnUrl"] = returnurl;
return View();
}
[HttpPost]
[AllowAnonymous]
public async Task<IActionResult> Login(LoginViewModel model, string? returnurl = null)
{
ViewData["ReturnUrl"] = returnurl;
returnurl ??= Url.Content("~/");
if (ModelState.IsValid)
{
var user = await _userManager.FindByNameAsync(model.UserName);
var result = await _signInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, lockoutOnFailure: true);
if (result.Succeeded)
{
if (user.TwoFactorEnabled==false)
{
return RedirectToAction(nameof(EnableAuthenticator), new { returnurl, model.RememberMe });
}
return LocalRedirect(returnurl);
}
if (result.RequiresTwoFactor)
{
return RedirectToAction(nameof(VerifyAuthenticatorCode), new { returnurl, model.RememberMe });
}
if (result.IsLockedOut)
{
return View("Lockout");
}
else
{
ModelState.AddModelError(string.Empty, "Invalid login attempt.");
return View(model);
}
}
return View(model);
}
Enable 2FA Controller Methods
[HttpGet]
public async Task<IActionResult> EnableAuthenticator()
{
string AuthenticatorUriFormat = "MY-OTP-SECRET-HERE";
var user = await _userManager.GetUserAsync(User);
await _userManager.ResetAuthenticatorKeyAsync(user);
var token = await _userManager.GetAuthenticatorKeyAsync(user);
string AuthenticatorUri = string.Format(AuthenticatorUriFormat, _urlEncoder.Encode("My-App-Name-Here"),
_urlEncoder.Encode(user.Email), token);
var model = new MFAViewModel() { Token = token, QRCodeUrl = AuthenticatorUri };
return View(model);
}
[HttpPost]
public async Task<IActionResult> EnableAuthenticator(MFAViewModel model)
{
if (ModelState.IsValid)
{
var user = await _userManager.GetUserAsync(User);
var succeeded = await _userManager.VerifyTwoFactorTokenAsync(user, _userManager.Options.Tokens.AuthenticatorTokenProvider, model.Code);
if (succeeded)
{
await _userManager.SetTwoFactorEnabledAsync(user, true);
}
else
{
ModelState.AddModelError("Verify", "Your two factor auth code could not be validated.");
return View(model);
}
}
return RedirectToAction(nameof(AuthenticatorConfirmation));
}
As mentioned in my comment, you could consider configuring the application use Claims-based authorization, after user login with 2FA successfully, you could add a claim store the 2FA login result and add it to the login user. After that, in your application, create a policy which requires the claim, and add the Authorize attribute on each controller.
Besides, you could also add the user's claims after 2FA , then create a custom middleware/Authorize attribute to validate each request and check whether the current user contains the claims or not. You can refer to the following links: Custom Authorization attributes and How To Override Attribute Class To Do Custom Authorization In .NET Core.

User.Identity.IsAuthenticated is false although SignInManager.PasswordSignInAsync() succeeds

I did find similar questions but none of the provided answers helped me.
I did follow a tutorial to add Identity to my ASP.net Core 2.2 project (https://retifrav.github.io/blog/2018/03/20/csharp-dotnet-core-identity-mysql/)
Even though SignInManager.PasswordSignInAsync() succeeds, both User.Identity.IsAuthenticated and SignInManager.IsSignedIn(User) are false in the _Layout view.
_Layout.cshtml:
#using Microsoft.AspNetCore.Identity
#inject SignInManager<MySiteUser> SignInManager
#inject UserManager<MysiteUser> UserManager
......................
<div>
#if (SignInManager.IsSignedIn(User))
{
<div>Hello #UserManager.GetUserName(User)!</div>
}
#if (User.Identity.IsAuthenticated)
{
<div>User is authenticated </div>
}
</div>
In Startup.CS, in ConfigureServices I have:
services.AddIdentity<MySiteUSer, MySiteRole>().AddEntityFrameworkStores<IdentityContext>().AddDefaultTokenProviders();
services.Configure<IdentityOptions>(options =>
{
options.Password.RequireDigit = true;
options.Password.RequiredLength = 8;
options.Password.RequireNonAlphanumeric = true;
options.Password.RequireUppercase = true;
options.Password.RequireLowercase = true;
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30);
options.Lockout.MaxFailedAccessAttempts = 10;
options.User.RequireUniqueEmail = true;
});
services.ConfigureApplicationCookie(options => options.LoginPath = "/Account/Login");
services.AddMvc();
In Startup.CS, in Configure() I have:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IServiceProvider services)
{
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseAuthentication(); ;
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
In AccountController I have:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
{
returnUrl = returnUrl ?? Url.Content("~/");
if (ModelState.IsValid)
{
var result = await _signInManager.PasswordSignInAsync(model.Username, model.Password, model.RememberMe, lockoutOnFailure: false);
if (result.Succeeded)
{
_logger.LogInformation("User logged in.");
var user = await _signInManager.UserManager.FindByNameAsync(model.Username);
var userPrincipal = await _signInManager.CreateUserPrincipalAsync(user);
var identity = userPrincipal.Identity;
if(identity.IsAuthenticated)
return RedirectToAction("Index", "Home");
}
else
{
ModelState.AddModelError(string.Empty, "Invalid login attempt.");
return View(model);
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
MySiteUser and MySiteRole just override default Identity classes
public class MySiteUser : IdentityUser<int>
{
}
public class MySiteRole : IdentityRole<int>
{
}
Edit:
Because all replies are about the Controller, before this one I used the following code in AccountController
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
{
returnUrl = returnUrl ?? Url.Content("~/");
if (ModelState.IsValid)
{
var result = await _signInManager.PasswordSignInAsync(model.Username, model.Password, model.RememberMe, lockoutOnFailure: false);
if (result.Succeeded)
{
return RedirectToAction("Index", "Home");
}
else
{
ModelState.AddModelError(string.Empty, "Invalid login attempt.");
return View(model);
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
The result was the same.
I've just find a solution, although I don't understand why it works. I've checked Chrome Developer Tools to see if the authentication cookie is set, and it wasn't.
After I deleted all cookies for the site, the app set the cookie and all works well.
I also tested the simpler AccountController and that works fine, too:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
{
returnUrl = returnUrl ?? Url.Content("~/");
if (ModelState.IsValid)
{
var result = await _signInManager
.PasswordSignInAsync(model.Username, model.Password,
Model.RememberMe, lockoutOnFailure: false);
if (result.Succeeded)
{
return RedirectToAction("Index", "Home");
}
else
{
ModelState.AddModelError(string.Empty, "Invalid login attempt.");
return View(model);
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
You don't need to check if(identity.IsAuthenticated) before redirecting user to home page. If the code reaches the (result.Succeeded) block, it means user is authenticated. if(identity.IsAuthenticated) will be true only at the end of the request, meaning you have returned an HttpResponse (or something) that will create a cookie on client side.
So the solution is to remove the condition inside the Login action.
/*if(identity.IsAuthenticated) <===== remove this */
return RedirectToAction("Index", "Home");
EDITS: Don't forget that when you use RedirectToAction, it's still a same request so the cookie will not be created yet. Instead, create and use a temporary success view as I usually do.
/*if(identity.IsAuthenticated) <===== remove this */
return RedirectToAction("Index", "Home"); <===== remove this */
/*put url in viewbag or use returnUrl variable*/
#ViewBag.ReturnUrl = Url.Action("index","home"/*,null,Request.Url.Scheme*/);
return View("LoginSuccess");
and here is what to put in your LoginSuccess.cshtml view
<h2>Authenticated. Wait 2 seconds or click continue</h2>
<p><a href="#ViewBag.ReturnUrl">
Continue</a></p>
<script>
setTimeout(function () {
window.location = "#ViewBag.ReturnUrl";
}, 2000)
</script>
PS: You may need to use partial view to avoid conflict with your layout page headers... return PartialView("LoginSuccess");
I believe I have stumbled on this answer to this. First try this in IE, it may work there. Apparently Chrome is quite fussy regarding the cookie that is used for the Authentication unless you are talking to it in HTTPS. If you are in development and using HTTP and using Chrome the IsSignedIn(User) may fail. This is unbelievably annoying and quite a productivity sink. HTH

Authourize tag does'nt maintain session state properly In Asp.net Core Identity ..

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using HMS_Context;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Http.Features;
using HMS_Service.Services.MasterService;
using HMS_Service.Services.PatientVisitService;
using HMS_Service.UserManagementService;
using HMS_Service.Services.PatientRegistrationService;
using HMS_Service.Services.BloodCampService;
using HMS_Service.Services.AccountService;
using System;
using Microsoft.AspNetCore.Identity;
using HMS_Presentation.Services;
using HMS_Service.Services.InventoryManagementService;
using HMS_Service.Services.SystemManagementService;
using HMS_Service.Services.UserManagementService;
using HMS_Service.Services.LabManagementService;
using HMS_Service.CacheSetting.AppSettings;
using HMS_Service.Services.BarCodeService;
namespace HMS_Presentation
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<IAppSettings, AppSettings>();
services.AddMemoryCache();
services.AddOptions();
services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));
services.AddDbContext<_DbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<HMS_POCO.UserManagement.ApplicationUser, HMS_POCO.UserManagement.ApplicationRole>(
option => {
option.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30);
option.Lockout.MaxFailedAccessAttempts = 5;
option.Lockout.AllowedForNewUsers = false;
})
.AddEntityFrameworkStores<HMS_Context._DbContext>()
.AddDefaultTokenProviders();
/*Cache Functionality Start*/
/*Cache Functionality End*/
services.AddAuthorization(options =>
{
options.AddPolicy("Administrator", policy => policy.RequireRole("Admin","Superior"));
options.AddPolicy("Doctors", policy => policy.RequireRole("Receptionist","Doctor", "Superior"));
options.AddPolicy("Nurses", policy => policy.RequireRole("Nurse", "Superior"));
options.AddPolicy("Labortory", policy => policy.RequireRole("LabTech", "Superior"));
options.AddPolicy("Accountants", policy => policy.RequireRole("Accountant", "Superior"));
options.AddPolicy("Receptionist", policy => policy.RequireRole("Receptionist", "Superior"));
options.AddPolicy("RecpDoct", policy => policy.RequireRole("Receptionist","Doctor", "Superior"));
options.AddPolicy("RMO", policy => policy.RequireRole("RMO", "Superior"));
options.AddPolicy("RD", policy => policy.RequireRole("RMO", "Doctor","Superior"));
// Access DNL(Doctor,Nurse ,Lab)
options.AddPolicy("AccessDNL", policy => policy.RequireRole("Doctor", "Nurse", "LabTech", "Superior"));
});
services.ConfigureApplicationCookie(options =>
{
options.Cookie.Name = "YourAppCookieName";
options.LoginPath = "/UserAccount/Login";
options.LogoutPath = "/UserAccount/Logout";
options.AccessDeniedPath = "/UserAccount/AccessDenied";
options.ReturnUrlParameter = CookieAuthenticationDefaults.ReturnUrlParameter;
});
services.AddDistributedMemoryCache();
services.AddSession(options=>options.Cookie.HttpOnly=true);
services.AddMvc().AddSessionStateTempDataProvider();
services.AddTransient<IEmailSender, EmailSender>();
services.Configure<FormOptions>(x => {
x.ValueLengthLimit = int.MaxValue;
x.MultipartBodyLengthLimit = long.MaxValue;
x.BufferBodyLengthLimit = long.MaxValue;
x.MemoryBufferThreshold = int.MaxValue;
x.ValueCountLimit = int.MaxValue;
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseSession();
app.UseStaticFiles();
app.UseAuthentication();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}
**User Account Controller**
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using HMS_Presentation.Services;
using Microsoft.Extensions.Logging;
using Microsoft.AspNetCore.Authentication;
using HMS_Presentation.Models.AccountViewModels;
using Microsoft.AspNetCore.Mvc.Rendering;
using System.Security.Claims;
using HMS_Service.UserManagementService;
using Microsoft.AspNetCore.Http;
using HMS_Service.Services.UserManagementService;
using HMS_POCO.UserManagement;
namespace HMS_Presentation.Controllers
{
[Authorize(Policy = "Administrator")]
[Route("[controller]/[action]")]
public class UserAccountController : Controller
{
private readonly UserManager<HMS_POCO.UserManagement.ApplicationUser> _userManager;
private readonly SignInManager<HMS_POCO.UserManagement.ApplicationUser> _signInManager;
private readonly IEmailSender _emailSender;
private readonly ILogger _logger;
private readonly RoleManager<HMS_POCO.UserManagement.ApplicationRole> _roleManager;
//Extra Addition
private readonly EmployeeService _employeeService;
private readonly UserAccessLogService _userAccessLogService;
public UserAccountController(
UserManager<HMS_POCO.UserManagement.ApplicationUser> userManager,
SignInManager<HMS_POCO.UserManagement.ApplicationUser> signInManager,
IEmailSender emailSender,
ILogger<UserAccountController> logger,
RoleManager<HMS_POCO.UserManagement.ApplicationRole> roleManager,
EmployeeService employeeService, UserAccessLogService userAccessLogService)
{
_userManager = userManager;
_signInManager = signInManager;
_emailSender = emailSender;
_logger = logger;
_roleManager = roleManager;
_employeeService = employeeService;
_userAccessLogService = userAccessLogService;
}
[TempData]
public string ErrorMessage { get; set; }
[HttpGet]
[AllowAnonymous]
public async Task<IActionResult> Login(string returnUrl = null)
{
// Clear the existing external cookie to ensure a clean login process
await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
ViewData["ReturnUrl"] = returnUrl;
return View();
}
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
{
USER_ACCESS_LOG be = new USER_ACCESS_LOG();
be.AccessTime = DateTime.Now.ToString();
be.UserName = model.Email;
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: true);
if (result.Succeeded)
{
var lookupUser = _userManager.Users.Where(c => c.UserName == model.Email).FirstOrDefault();
HttpContext.Session.SetInt32("UserId", lookupUser.EmpId);
_logger.LogInformation("User logged in.");
be.AccessedStatus = true;
_userAccessLogService.Add(be);
return RedirectToLocal(returnUrl);
}
if (result.RequiresTwoFactor)
{
var lookupUser = _userManager.Users.Where(c => c.UserName == model.Email).FirstOrDefault();
HttpContext.Session.SetInt32("UserId", lookupUser.EmpId);
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.");
be.AccessedStatus = false;
_userAccessLogService.Add(be);
return View(model);
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
[HttpGet]
[AllowAnonymous]
public async Task<IActionResult> LoginWith2fa(bool rememberMe, string returnUrl = null)
{
// Ensure the user has gone through the username & password screen first
var user = await _signInManager.GetTwoFactorAuthenticationUserAsync();
if (user == null)
{
throw new ApplicationException($"Unable to load two-factor authentication user.");
}
var model = new LoginWith2faViewModel { RememberMe = rememberMe };
ViewData["ReturnUrl"] = returnUrl;
return View(model);
}
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> LoginWith2fa(LoginWith2faViewModel model, bool rememberMe, string returnUrl = null)
{
if (!ModelState.IsValid)
{
return View(model);
}
var user = await _signInManager.GetTwoFactorAuthenticationUserAsync();
if (user == null)
{
throw new ApplicationException($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
}
var authenticatorCode = model.TwoFactorCode.Replace(" ", string.Empty).Replace("-", string.Empty);
var result = await _signInManager.TwoFactorAuthenticatorSignInAsync(authenticatorCode, rememberMe, model.RememberMachine);
if (result.Succeeded)
{
_logger.LogInformation("User with ID {UserId} logged in with 2fa.", user.Id);
return RedirectToLocal(returnUrl);
}
else if (result.IsLockedOut)
{
_logger.LogWarning("User with ID {UserId} account locked out.", user.Id);
return RedirectToAction(nameof(Lockout));
}
else
{
_logger.LogWarning("Invalid authenticator code entered for user with ID {UserId}.", user.Id);
ModelState.AddModelError(string.Empty, "Invalid authenticator code.");
return View();
}
}
[HttpGet]
[AllowAnonymous]
public async Task<IActionResult> LoginWithRecoveryCode(string returnUrl = null)
{
// Ensure the user has gone through the username & password screen first
var user = await _signInManager.GetTwoFactorAuthenticationUserAsync();
if (user == null)
{
throw new ApplicationException($"Unable to load two-factor authentication user.");
}
ViewData["ReturnUrl"] = returnUrl;
return View();
}
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> LoginWithRecoveryCode(LoginWithRecoveryCodeViewModel model, string returnUrl = null)
{
if (!ModelState.IsValid)
{
return View(model);
}
var user = await _signInManager.GetTwoFactorAuthenticationUserAsync();
if (user == null)
{
throw new ApplicationException($"Unable to load two-factor authentication user.");
}
var recoveryCode = model.RecoveryCode.Replace(" ", string.Empty);
var result = await _signInManager.TwoFactorRecoveryCodeSignInAsync(recoveryCode);
if (result.Succeeded)
{
_logger.LogInformation("User with ID {UserId} logged in with a recovery code.", user.Id);
return RedirectToLocal(returnUrl);
}
if (result.IsLockedOut)
{
_logger.LogWarning("User with ID {UserId} account locked out.", user.Id);
return RedirectToAction(nameof(Lockout));
}
else
{
_logger.LogWarning("Invalid recovery code entered for user with ID {UserId}", user.Id);
ModelState.AddModelError(string.Empty, "Invalid recovery code entered.");
return View();
}
}
[HttpGet]
[AllowAnonymous]
public IActionResult Lockout()
{
return View();
}
[HttpGet]
public IActionResult Register(string returnUrl = null)
{
ViewData["RoleName"] = new SelectList(_roleManager.Roles, "Id", "Name");
ViewData["EmployeeName"] = new SelectList(_employeeService.GetUnRegisteredEmployee(), "Id", "FirstName");
ViewData["ReturnUrl"] = returnUrl;
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Register(RegisterViewModel model, string returnUrl = null)
{
ViewData["ReturnUrl"] = returnUrl;
if (ModelState.IsValid)
{
var user = new HMS_POCO.UserManagement.ApplicationUser { UserName = model.Email, Email = model.Email, EmpId=model.EmployeeId};
var result = await _userManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
IdentityRole res = await _roleManager.FindByIdAsync(model.RoleId);
await _userManager.AddToRoleAsync(user, res.Name);
_logger.LogInformation("User created a new account with password.");
return RedirectToLocal(returnUrl);
}
AddErrors(result);
}
ViewData["RoleName"] = new SelectList(_roleManager.Roles, "Id", "Name");
ViewData["EmployeeName"] = new SelectList(_employeeService.GetAll(), "Id", "FirstName");
return View(model);
}
[AllowAnonymous]
public async Task<IActionResult> Logout()
{
HttpContext.Session.Clear();
await _signInManager.SignOutAsync();
_logger.LogInformation("User logged out.");
return RedirectToAction(nameof(HomeController.Index), "Home");
}
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public IActionResult ExternalLogin(string provider, string returnUrl = null)
{
// Request a redirect to the external login provider.
var redirectUrl = Url.Action(nameof(ExternalLoginCallback), "Account", new { returnUrl });
var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl);
return Challenge(properties, provider);
}
[HttpGet]
[AllowAnonymous]
public async Task<IActionResult> ExternalLoginCallback(string returnUrl = null, string remoteError = null)
{
if (remoteError != null)
{
ErrorMessage = $"Error from external provider: {remoteError}";
return RedirectToAction(nameof(Login));
}
var info = await _signInManager.GetExternalLoginInfoAsync();
if (info == null)
{
return RedirectToAction(nameof(Login));
}
// Sign in the user with this external login provider if the user already has a login.
var result = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false, bypassTwoFactor: true);
if (result.Succeeded)
{
_logger.LogInformation("User logged in with {Name} provider.", info.LoginProvider);
return RedirectToLocal(returnUrl);
}
if (result.IsLockedOut)
{
return RedirectToAction(nameof(Lockout));
}
else
{
// If the 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 });
}
}
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> ExternalLoginConfirmation(ExternalLoginViewModel model, string returnUrl = null)
{
if (ModelState.IsValid)
{
// Get the information about the user from the external login provider
var info = await _signInManager.GetExternalLoginInfoAsync();
if (info == null)
{
throw new ApplicationException("Error loading external login information during confirmation.");
}
var user = new HMS_POCO.UserManagement.ApplicationUser { UserName = model.Email, Email = model.Email };
var result = await _userManager.CreateAsync(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 RedirectToLocal(returnUrl);
}
}
AddErrors(result);
}
ViewData["ReturnUrl"] = returnUrl;
return View(nameof(ExternalLogin), model);
}
[HttpGet]
[AllowAnonymous]
public async Task<IActionResult> ConfirmEmail(string userId, string code)
{
if (userId == null || code == null)
{
return RedirectToAction(nameof(HomeController.Index), "Home");
}
var user = await _userManager.FindByIdAsync(userId);
if (user == null)
{
throw new ApplicationException($"Unable to load user with ID '{userId}'.");
}
var result = await _userManager.ConfirmEmailAsync(user, code);
return View(result.Succeeded ? "ConfirmEmail" : "Error");
}
[HttpGet]
[AllowAnonymous]
public IActionResult ForgotPassword()
{
return View();
}
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> ForgotPassword(ForgotPasswordViewModel model)
{
if (ModelState.IsValid)
{
var user = await _userManager.FindByEmailAsync(model.Email);
if (user == null || !(await _userManager.IsEmailConfirmedAsync(user)))
{
// Don't reveal that the user does not exist or is not confirmed
return RedirectToAction(nameof(ForgotPasswordConfirmation));
}
// For more information on how to enable account confirmation and password reset please
// visit https://go.microsoft.com/fwlink/?LinkID=532713
var code = await _userManager.GeneratePasswordResetTokenAsync(user);
var callbackUrl = Url.ResetPasswordCallbackLink(user.Id, code, Request.Scheme);
await _emailSender.SendEmailAsync(model.Email, "Reset Password",
$"Please reset your password by clicking here: <a href='{callbackUrl}'>link</a>");
return RedirectToAction(nameof(ForgotPasswordConfirmation));
}
// If we got this far, something failed, redisplay form
return View(model);
}
[HttpGet]
[AllowAnonymous]
public IActionResult ForgotPasswordConfirmation()
{
return View();
}
[HttpGet]
[AllowAnonymous]
public IActionResult ResetPassword(string code = null)
{
if (code == null)
{
throw new ApplicationException("A code must be supplied for password reset.");
}
var model = new ResetPasswordViewModel { Code = code };
return View(model);
}
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> ResetPassword(ResetPasswordViewModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
var user = await _userManager.FindByEmailAsync(model.Email);
if (user == null)
{
// Don't reveal that the user does not exist
return RedirectToAction(nameof(ResetPasswordConfirmation));
}
var result = await _userManager.ResetPasswordAsync(user, model.Code, model.Password);
if (result.Succeeded)
{
return RedirectToAction(nameof(ResetPasswordConfirmation));
}
AddErrors(result);
return View();
}
[HttpGet]
[AllowAnonymous]
public IActionResult ResetPasswordConfirmation()
{
return View();
}
[HttpGet]
public IActionResult AccessDenied()
{
return View();
}
#region Helpers
private void AddErrors(IdentityResult result)
{
foreach (var error in result.Errors)
{
ModelState.AddModelError(string.Empty, error.Description);
}
}
private IActionResult RedirectToLocal(string returnUrl)
{
if (Url.IsLocalUrl(returnUrl))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction(nameof(HomeController.Index), "Home");
}
}
#endregion
}
}
This is my code of Startup.cs file. and User Account Controller The authorize tag Does not maintain the session state properly .. Even after passing the session time the application starts without email and password required . How to fix it . i am using .NET CORE and visual studio 2017 and when i logout and then run the application it works Fine and take email and password. but without logout the account and close the tab and then run the application issue appears ...
Use IsPersistent=true in default signin method mentioned below:
var result = await _signInManager.PasswordSignInAsync(user, model.LoginPassword, true, false);
Here the third parameter is IsPersistent, which should be true for persistent login.