Reputation: 2385
The Microsoft.AspNet.Identity.PasswordValidator is configurable with a number of parameters which define the minimum password length and complexity rules. If the user enters a password that does not meet the criteria, PasswordValidator will throw an exception which describes the violation, but it provides no other way to describe the rules to a user (e.g. "Passwords must be 8-12 characters and must include ..." etc).
I searched StackOverflow and the web in general figuring there must be hundreds of examples out there of what I need, but it's beginning to look like I'm the only person who has ever needed this, which I know isn't the case. Before I write my own implementation, I just have to ask...
Am I completely overlooking an accepted "standard" answer to this problem?
Upvotes: 0
Views: 604
Reputation: 2385
Here's what I came up with since I needed to get something working, and wasn't finding the canned standard answer I was looking for. I implemented it as an extension over the PasswordValidator class for convenience, although that's not strictly necessary.
public static string ToDescription(this PasswordValidator validator)
{
var options = new List<string>();
if (validator.RequireUppercase) options.Add("upper-case letters");
if (validator.RequireLowercase) options.Add("lower-case letters");
if (validator.RequireDigit) options.Add("numbers");
if (validator.RequireNonLetterOrDigit) options.Add("special characters");
var result = "Passwords must be at least "
+ validator.RequiredLength + " characters long"
+ (options.Any() ? ", and include " + options.OxfordJoin() : ".");
return result;
}
I also added the OxfordJoin extension to turn the list of requirements into a nicely formatted sentence:
public static string OxfordJoin(this IEnumerable<string> source)
{
var array = source.ToArray();
var joined = string.Join(", ", array);
var result = (array.Length > 2)
? joined.ReplaceLast(",", ", and")
: joined.ReplaceLast(",", " and");
return result;
}
...and finally a "so standard it should just be in the framework already" ReplaceLast implementation:
public static string ReplaceLast(this string value, string oldValue, string newValue)
{
var position = value.LastIndexOf(oldValue, StringComparison.InvariantCultureIgnoreCase);
var result = (position > -1)
? value.Substring(0, position) + newValue + value.Substring(position + 1)
: value;
return result;
}
Upvotes: 0
Reputation: 153
It may sound a bit hackish but sending an empty string to ValidateAsync() method of PasswordValidator will do the work. Example of UserManager with default configuration :
var rules = await UserManager.PasswordValidator.ValidateAsync("");
rules.Errors.First() :
Passwords must be at least 6 characters.
Passwords must have at least one non letter or digit character.
Passwords must have at least one digit ('0'-'9').
Passwords must have at least one lowercase ('a'-'z').
Passwords must have at least one uppercase ('A'-'Z').
you can even list them
var list = rules.Errors.First().Split('.');
Upvotes: 1