I have a class called PasswordChangeChecker.cs
that has a method that returns from the database whether or not a user has changed their password. The signature for that method is:
public bool IsPasswordChangedFromInitial(string IdOfUser)
where IdOfUser
is the Id field from the Identity framework User. If it returns true, that means the change password page should not be displayed, otherwise, it should navigate to the change password form. Once the user successfully changes their password, the database flag gets set appropriately, and they should not be prompted for a password change again (unless manually forced to by an admin). How can I put this method in the RouteConfig.cs
file, where currently I have:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
namespace IdentityDevelopment
{
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
}
How can I add a conditional construct into the defaults
parameter so I can use the IsPasswordChangedFromInitial
method to decide whether or not to go to the password change page? That page is at /Account/ChangePassword
.
EDIT
As per the comments, the appropriate action methods for my specific need are (I have omitted irrelevant code):
Login post action:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginModel details, string returnUrl)
{
if (ModelState.IsValid)
{
AppUser user = await UserManager.FindAsync(details.Name,
details.Password);
if (user == null)
{
AppUser userByName = await UserManager.FindByNameAsync(details.Name);
if(userByName == null)
{
ModelState.AddModelError("", "Invalid username.");
}
else
{
//If this else is reached, it means the password entered is invalid.
//code for incrementing count of failed attempts and navigation to lock out page if needed
}
}
else
{
if(user.LockedOut)
{
//navigate to locked out page
}
else
{
PasswordChangeChecker PassCheck = new PasswordChangeChecker();
string userId = user.Id.ToString();
bool proceed = PassCheck.IsPasswordChangedFromInitial(userId);
//Authorize the user
ClaimsIdentity ident = await UserManager.CreateIdentityAsync(user,
DefaultAuthenticationTypes.ApplicationCookie);
ident.AddClaims(LocationClaimsProvider.GetClaims(ident));
ident.AddClaims(ClaimsRoles.CreateRolesFromClaims(ident));
AuthManager.SignOut();
AuthManager.SignIn(new AuthenticationProperties
{
IsPersistent = false
}, ident);
//persist login into db code
if (proceed)
{
//reset failed logins count
return Redirect(returnUrl);
}
else
{
return ChangePassword();
}
}
}
}
ViewBag.returnUrl = returnUrl;
return View(details);
}
ChangePassword() get action:
[HttpGet]
[Authorize]
public ActionResult ChangePassword()
{
return View();
}
Somehow the view returned is the view in the RouteConfig.cs
instead of the ChangePassword.cshtml
page.
Thank you.
I would do it with global action filters
you can make a action filter with method
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (showChagePwPage)
{
//redirect to the change password page
filterContext.Result = new RedirectToActionResult("ChangePassword", "Account");
}
base.OnActionExecuting(filterContext);
}
and then adding it into global action filter by
GlobalFilters.Filters.Add(yourFilterContext);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With