DeviceManager/DeviceRepair.Models/PasswordStrategy.cs

351 lines
13 KiB
C#
Raw Permalink Normal View History

2024-05-28 14:36:38 +00:00
using System;
using System.Linq;
using System.Text.RegularExpressions;
namespace DeviceRepair.Models
{
/// <summary>
/// 密码策略对象
/// (目前没有存入后台数据库,目前基于客户端判断)
/// </summary>
public class PasswordStrategy
{
private static PasswordStrategy manager;
public static PasswordStrategy Instance
{
get
{
if (manager == null)
manager = new PasswordStrategy();
return manager;
}
}
#region Fields & Property
/// <summary>
/// 默认的特殊字符集
/// </summary>
private char[] DefaultSpecialCharacters = new char[]
{
'~','`','!','@','#','$','%','^','&','*','(',')','-','_','+','-','[',']','{','}','|','\\',':',';','"','\'','<','>','.','/','?'
};
/// <summary>
/// 最小密码长度
/// </summary>
public int PasswordMinLength
{
get;
set;
}
/// <summary>
/// 密码策略类型
/// </summary>
public PasswordStrategyType StrategyType
{
get;
set;
}
/// <summary>
/// 最小密码策略组合类型种类
/// </summary>
public int MinPasswordStrategyTypeCounts
{
get;
set;
}
/// <summary>
/// 密码有效期限
/// (以天为单位)
/// </summary>
public int PasswordValidDays
{
get; set;
}
/// <summary>
/// 密码错误连续重试次数
/// (超过连续重试次数后,账号将被锁定)
/// </summary>
public int PasswordContinueRetryCounts
{
get; set;
}
/// <summary>
/// 密码修改不允许重复的次数
/// 默认连续5次密码修改不允许相同
/// </summary>
public int PasswordAlterUnRepeatCounts
{
get; set;
}
/// <summary>
/// 系统允许的屏幕最大闲置时间(以分钟为单位)
/// (超过规定时间,系统屏幕将被锁定,需要账号登陆解锁屏幕)
/// </summary>
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
/// <summary>
/// 密码校验
/// </summary>
/// <param name="password"></param>
/// <param name="msg"></param>
/// <returns></returns>
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}");
}
}
/// <summary>
/// 校验密码是否符合单一密码策略
/// </summary>
/// <param name="password"></param>
/// <param name="strategyType"></param>
/// <returns></returns>
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
/// <summary>
/// 随机产生符合当前密码策略的密码
/// </summary>
/// <returns></returns>
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);
}
/// <summary>
/// 按照密码策略随机产生指定位数的字符
/// </summary>
/// <param name="pwdStrategyType">密码策略</param>
/// <param name="iRandomLength">随机位数</param>
/// <returns></returns>
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;
}
/// <summary>
/// 随机生成字母
/// </summary>
/// <param name="iRandomLength">生成长度</param>
/// <param name="bLower">是否小写字母</param>
/// <returns></returns>
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;
}
/// <summary>
/// 随机生成数字
/// </summary>
/// <param name="iRandomLength"></param>
/// <returns></returns>
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;
}
/// <summary>
/// 随机生成特殊字符
/// </summary>
/// <param name="iRandomLength">生成长度</param>
/// <returns></returns>
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
}
}