using System; using System.Linq; using System.Text.RegularExpressions; namespace DeviceRepair.Models { /// /// 密码策略对象 /// (目前没有存入后台数据库,目前基于客户端判断) /// public class PasswordStrategy { private static PasswordStrategy manager; public static PasswordStrategy Instance { get { if (manager == null) manager = new PasswordStrategy(); return manager; } } #region Fields & Property /// /// 默认的特殊字符集 /// private char[] DefaultSpecialCharacters = new char[] { '~','`','!','@','#','$','%','^','&','*','(',')','-','_','+','-','[',']','{','}','|','\\',':',';','"','\'','<','>','.','/','?' }; /// /// 最小密码长度 /// public int PasswordMinLength { get; set; } /// /// 密码策略类型 /// public PasswordStrategyType StrategyType { get; set; } /// /// 最小密码策略组合类型种类 /// public int MinPasswordStrategyTypeCounts { get; set; } /// /// 密码有效期限 /// (以天为单位) /// public int PasswordValidDays { get; set; } /// /// 密码错误连续重试次数 /// (超过连续重试次数后,账号将被锁定) /// public int PasswordContinueRetryCounts { get; set; } /// /// 密码修改不允许重复的次数 /// (默认:连续5次密码修改不允许相同) /// public int PasswordAlterUnRepeatCounts { get; set; } /// /// 系统允许的屏幕最大闲置时间(以分钟为单位) /// (超过规定时间,系统屏幕将被锁定,需要账号登陆解锁屏幕) /// public int ScreenLockTimes { get; set; } #endregion #region Ctor public PasswordStrategy(PasswordStrategyType strategyType = PasswordStrategyType.UpperCaseLetter | PasswordStrategyType.LowerCaseLetter | PasswordStrategyType.Number | PasswordStrategyType.SpecialCharacter, int passwordMinLength = 8, int minPasswordStrategyTypeCounts = 3, int passwordValidDays = 90, int passwordContinueRetryCounts = 5, int passwordAlterUnRepeatCounts = 5, int screenLockTimes = 15) { StrategyType = strategyType; PasswordMinLength = passwordMinLength; MinPasswordStrategyTypeCounts = minPasswordStrategyTypeCounts; PasswordValidDays = passwordValidDays; PasswordContinueRetryCounts = passwordContinueRetryCounts; PasswordAlterUnRepeatCounts = passwordAlterUnRepeatCounts; ScreenLockTimes = screenLockTimes; } #endregion #region Methods /// /// 密码校验 /// /// /// /// public bool Validate(string password, out string msg) { try { msg = "密码校验成功!"; if (string.IsNullOrEmpty(password)) { msg = "密码为空!"; return false; } if (password.Length < PasswordMinLength) { msg = $"密码至少位{PasswordMinLength}位!"; return false; } #region 校验密码强度 int iCurrentPasswordIntensity = 0; if ((StrategyType & PasswordStrategyType.UpperCaseLetter) != 0) { //策略中要求大写字母验证 if (CheckCharacter(password, PasswordStrategyType.UpperCaseLetter)) { iCurrentPasswordIntensity++; } } if ((StrategyType & PasswordStrategyType.LowerCaseLetter) != 0) { //策略中要求小写字母验证 if (CheckCharacter(password, PasswordStrategyType.LowerCaseLetter)) { iCurrentPasswordIntensity++; } } if ((StrategyType & PasswordStrategyType.Number) != 0) { //策略中要求数字验证 if (CheckCharacter(password, PasswordStrategyType.Number)) { iCurrentPasswordIntensity++; } } if ((StrategyType & PasswordStrategyType.SpecialCharacter) != 0) { //策略中要求特殊字符验证 if (CheckCharacter(password, PasswordStrategyType.SpecialCharacter)) { iCurrentPasswordIntensity++; } } if (iCurrentPasswordIntensity < MinPasswordStrategyTypeCounts) { msg = $"密码不合符密码强度策略(大写字母/小写字母/数字/特殊字符中最好满足其中{MinPasswordStrategyTypeCounts}种)!"; return false; } #endregion return true; } catch (Exception ex) { throw new Exception($"密码校验时发生异常:{ex.Message}"); } } /// /// 校验密码是否符合单一密码策略 /// /// /// /// private bool CheckCharacter(string password, PasswordStrategyType strategyType) { string regexExpresion = string.Empty; switch (strategyType) { case PasswordStrategyType.UpperCaseLetter: regexExpresion = "[A-Z]"; break; case PasswordStrategyType.LowerCaseLetter: regexExpresion = "[a-z]"; break; case PasswordStrategyType.Number: regexExpresion = "[0-9]"; break; case PasswordStrategyType.SpecialCharacter: if ((password.Where(A => { return DefaultSpecialCharacters.Contains(A); })?.Count() ?? 0) > 0) { return true; } else { return false; } default: break; } return Regex.IsMatch(password, regexExpresion); } #region 随机产生符合当前密码策略的密码 /// /// 随机产生符合当前密码策略的密码 /// /// public string GenRandomPassword() { string vPwdTmp = string.Empty; if ((StrategyType & PasswordStrategyType.UpperCaseLetter) != 0) { vPwdTmp += GetRandomCharByStrategy(PasswordStrategyType.UpperCaseLetter, (new Random(~unchecked((int)DateTime.Now.Ticks))).Next(3, 5)); } if ((StrategyType & PasswordStrategyType.LowerCaseLetter) != 0) { vPwdTmp += GetRandomCharByStrategy(PasswordStrategyType.LowerCaseLetter, (new Random(~unchecked((int)DateTime.Now.Ticks))).Next(3, 5)); } if ((StrategyType & PasswordStrategyType.Number) != 0) { vPwdTmp += GetRandomCharByStrategy(PasswordStrategyType.Number, (new Random(~unchecked((int)DateTime.Now.Ticks))).Next(3, 5)); } if ((StrategyType & PasswordStrategyType.SpecialCharacter) != 0) { vPwdTmp += GetRandomCharByStrategy(PasswordStrategyType.SpecialCharacter, (new Random(~unchecked((int)DateTime.Now.Ticks))).Next(3, 5)); } if (vPwdTmp.Length < PasswordMinLength) { vPwdTmp += RandomString.GetRandomString(PasswordMinLength - vPwdTmp.Length, ((StrategyType & PasswordStrategyType.Number) != 0), ((StrategyType & PasswordStrategyType.LowerCaseLetter) != 0), ((StrategyType & PasswordStrategyType.UpperCaseLetter) != 0), ((StrategyType & PasswordStrategyType.SpecialCharacter) != 0)); } return RandomString.RandomChangeStringSequence(vPwdTmp); } /// /// 按照密码策略随机产生指定位数的字符 /// /// 密码策略 /// 随机位数 /// private string GetRandomCharByStrategy(PasswordStrategyType pwdStrategyType, int iRandomLength) { string vRandStrPwd = string.Empty; switch (pwdStrategyType) { case PasswordStrategyType.UpperCaseLetter: vRandStrPwd = GenerateRandomLetter(iRandomLength); break; case PasswordStrategyType.LowerCaseLetter: vRandStrPwd = GenerateRandomLetter(iRandomLength, true); break; case PasswordStrategyType.Number: vRandStrPwd = GenerateCheckCodeNum(iRandomLength); break; case PasswordStrategyType.SpecialCharacter: vRandStrPwd = GenerateRandomSpecialCharacter(iRandomLength); break; default: break; } return vRandStrPwd; } /// /// 随机生成字母 /// /// 生成长度 /// 是否小写字母 /// private string GenerateRandomLetter(int iRandomLength, bool bLower = false) { char[] Pattern = new char[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' }; if (bLower) { Pattern = new char[] { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' }; } string result = ""; int n = Pattern.Length; Random random = new Random(~unchecked((int)DateTime.Now.Ticks)); for (int i = 0; i < iRandomLength; i++) { int rnd = random.Next(0, n); result += Pattern[rnd]; } return result; } /// /// 随机生成数字 /// /// /// private string GenerateCheckCodeNum(int iRandomLength) { int rep = 0; string str = string.Empty; long num2 = DateTime.Now.Ticks + rep; rep++; Random random = new Random(((int)(((ulong)num2) & 0xffffffffL)) | ((int)(num2 >> rep))); for (int i = 0; i < iRandomLength; i++) { int num = random.Next(); str = str + ((char)(0x30 + ((ushort)(num % 10)))).ToString(); } return str; } /// /// 随机生成特殊字符 /// /// 生成长度 /// private string GenerateRandomSpecialCharacter(int iRandomLength) { string result = ""; int n = DefaultSpecialCharacters.Length; Random random = new Random(~unchecked((int)DateTime.Now.Ticks)); for (int i = 0; i < iRandomLength; i++) { int rnd = random.Next(0, n); result += DefaultSpecialCharacters[rnd]; } return result; } #endregion #endregion } }