DeviceManager/DeviceRepair.Models/PasswordStrategy.cs
2024-05-28 22:36:38 +08:00

351 lines
13 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}
}