actualmente estoy construyendo aplicaciones web para locales. Cuando creo un nuevo usuario, configuro el usuario con la contraseña predeterminada. Y quiero hacerlo, si el usuario inicia sesión con la contraseña predeterminada, se redirigirá a la página Cambiar contraseña. Y el usuario no podrá acceder a ninguna página hasta que cambie la contraseña.
Mi solución actual es verificar en cada controlador, ¿hay alguna forma inteligente de hacer esto?
Aquí hay un código después de iniciar sesión
[HttpPost] [AllowAnonymous] [ValidateAntiForgeryToken] public async Task<IActionResult> Login([FromForm] LoginViewModel vm, string returnUrl = null) { if (ModelState.IsValid) { var result = await repository.Login(vm); if (result.IsSuccess) { await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, result.Data, new AuthenticationProperties { IssuedUtc = DateTime.UtcNow, ExpiresUtc = DateTime.UtcNow.AddDays(1), IsPersistent = false }); if (vm.Password != Password.DefaultPassword) { return RedirectToLocal(returnUrl); } else { return RedirectToAction(nameof(UserController.NewPassword)); } } else { ViewBag.ErrorMessage = result.ErrorMessage; } } return View(vm); } Para el otro controlador, siempre verificamos la contraseña de la sesión. Si la contraseña es la misma que la contraseña predeterminada, la redirigimos a la página NewPassword
¡Gracias por adelantado!
Puede almacenar la contraseña de usuario usando la session como se muestra a continuación
HttpContext.Session.SetString("Password", vm.password);Luego cree un filtro para verificar si el usuario inicia sesión con la contraseña predeterminada o no
public class PasswordFilter: IAuthorizationFilter { private readonly IHttpContextAccessor _httpContextAccessor; private readonly ISession _session; public PasswordFilter(IHttpContextAccessor httpContextAccessor) { _httpContextAccessor = httpContextAccessor; _session = _httpContextAccessor.HttpContext.Session; } public void OnAuthorization(AuthorizationFilterContext context) { if (_session.GetString("Password") == Password.DefaultPassword) { context.Result = new RedirectResult(nameof(UserController.NewPassword)); } } }Finalmente, puede usar este filtro agregando este atributo a sus controladores
[TypeFilter(typeof(PasswordFilter))]Espero que este enfoque logre su objetivo.
Como dijo @JHBonarius, mi solución actual ahora es usar Middleware personalizado para redirigir a la página de nueva contraseña.
Mi middleware se ve así:
public class CheckPasswordMiddleware { private readonly RequestDelegate next; public CheckPasswordMiddleware(RequestDelegate next) { this.next = next; } public async Task Invoke(HttpContext context) { if (context.Request.Path != "/User/NewPassword" && context.User.Identity.IsAuthenticated) { var userId = context.User.Identity.GetUserId(); if (!string.IsNullOrEmpty(userId)) { var dbContext = context.RequestServices.GetRequiredService<DatabaseContext>(); var passwordHash = await dbContext.User.Where(x => x.Id.ToLower() == userId.ToLower()).Select(x => x.Password).FirstOrDefaultAsync(); if (Hash.Verify(Password.DefaultPassword, passwordHash)) { context.Response.Redirect("/User/NewPassword"); } } } await next(context); } }y ahora puedo deshacerme del cheque en mi otro controlador, y mi inicio de sesión se verá así:
[HttpPost] [AllowAnonymous] [ValidateAntiForgeryToken] public async Task<IActionResult> Login([FromForm] LoginViewModel vm, string returnUrl = null) { if (ModelState.IsValid) { var result = await repository.Login(vm); if (result.IsSuccess) { await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, result.Data, new AuthenticationProperties { IssuedUtc = DateTime.UtcNow, ExpiresUtc = DateTime.UtcNow.AddDays(1), IsPersistent = false }); return RedirectToLocal(returnUrl); } else { ViewBag.ErrorMessage = result.ErrorMessage; } } return View(vm); }Espero que esto ayude a cualquiera que quiera lograr los mismos objetivos.
¡Gracias!