ASP.NET&Spring.NET&NHibernate最佳实践(十九)——第4章权限子系统(12)
ASP.NET&Spring.NET&NHibernate最佳实践(十九)——第4章权限子系统(12)
成员资格信息提供类(HibernateMembershipProvider.cs)
using System;
using System.Collections.Generic;
using System.Text;
using System.Web.Security;
using System.Collections.Specialized;
using System.Configuration.Provider;
using System.Text.RegularExpressions;
using Guushuuse.SalaryPrj.Security.Service;
using System.Collections;
using System.Globalization;
using Guushuuse.SalaryPrj.Security.DomainModel;
using System.Security.Cryptography;
namespace Guushuuse.SalaryPrj.Security.Providers
{
/**//// <summary>
///管理数据库中 ASP.NET 应用程序的成员资格信息存储
/// </summary>
public class HibernateMembershipProvider : MembershipProvider
{
private string _applicationName;
private bool _enablePasswordReset;
private bool _enablePasswordRetrieval;
private int _maxInvalidPasswordAttempts;
private int _minRequiredNonAlphanumericCharacters;
private int _minRequiredPasswordLength;
private int _passwordAttemptWindow;
private MembershipPasswordFormat _passwordFormat;
private string _passwordStrengthRegularExpression;
private bool _requiresQuestionAndAnswer;
private bool _requiresUniqueEmail;
属性#region 属性
/**//// <summary>
/// 获取或设置要存储和检索其成员资格信息的应用程序的名称
/// </summary>
public override string ApplicationName
{
get
{
return _applicationName;
}
set
{
if (String.IsNullOrEmpty(value))
{
throw new ArgumentNullException("Provider application name not null.");
}
if (value.Length > 255)
{
throw new ProviderException("Provider application name too long.");
}
_applicationName = value;
}
}
/**//// <summary>
/// 获取一个值,指示成员资格提供程序是否配置为允许用户重置其密码
/// </summary>
public override bool EnablePasswordReset
{
get { return _enablePasswordReset; }
}
/**//// <summary>
/// 获取一个值,指示成员资格提供程序是否配置为允许用户检索其密码
/// </summary>
public override bool EnablePasswordRetrieval
{
get { return _enablePasswordRetrieval; }
}
/**//// <summary>
/// 获取锁定成员资格用户前允许的无效密码或无效密码提示问题答案尝试次数
/// </summary>
public override int MaxInvalidPasswordAttempts
{
get { return _maxInvalidPasswordAttempts; }
}
/**//// <summary>
/// 获取有效密码中必须包含的最少特殊字符数
/// </summary>
public override int MinRequiredNonAlphanumericCharacters
{
get { return _minRequiredNonAlphanumericCharacters; }
}
/**//// <summary>
/// 获取密码所要求的最小长度
/// </summary>
public override int MinRequiredPasswordLength
{
get { return _minRequiredPasswordLength; }
}
/**//// <summary>
/// 获取在锁定成员资格用户之前允许的最大无效密码或无效密码提示问题答案尝试次数的分钟数
/// </summary>
public override int PasswordAttemptWindow
{
get { return _passwordAttemptWindow; }
}
/**//// <summary>
/// 获取一个值,表示用于在成员资格数据库中存储密码的格式
/// </summary>
public override MembershipPasswordFormat PasswordFormat
{
get { return _passwordFormat; }
}
/**//// <summary>
/// 获取用于计算密码的正则表达式
/// </summary>
public override string PasswordStrengthRegularExpression
{
get { return _passwordStrengthRegularExpression; }
}
/**//// <summary>
/// 获取一个值,指示成员资格提供程序是否配置为要求用户在进行密码重置和检索时回答密码提示问题
/// </summary>
public override bool RequiresQuestionAndAnswer
{
get { return _requiresQuestionAndAnswer; }
}
/**//// <summary>
/// 获取一个值,指示成员资格提供程序是否配置为要求每个用户名具有唯一的电子邮件地址
/// </summary>
public override bool RequiresUniqueEmail
{
get { return _requiresUniqueEmail; }
}
#endregion 属性
方法#region 方法
/**//// <summary>
/// 使用 ASP.NET 应用程序配置文件中指定的属性值初始化成员资格提供程序
/// </summary>
/// <param name="name"></param>
/// <param name="config"></param>
public override void Initialize(string name, NameValueCollection config)
{
if (config == null)
{
throw new ArgumentNullException("config");
}
if (String.IsNullOrEmpty(name))
{
name = "HibernateMembershipProvider";
}
if (String.IsNullOrEmpty(config["description"]))
{
config.Remove("description");
config.Add("description", "GFC.Security Membership Provider");
}
base.Initialize(name, config);
this._enablePasswordRetrieval = SecUtility.GetBooleanValue(config, "enablePasswordRetrieval", false);
this._enablePasswordReset = SecUtility.GetBooleanValue(config, "enablePasswordReset", true);
this._requiresQuestionAndAnswer = SecUtility.GetBooleanValue(config, "requiresQuestionAndAnswer", true);
this._requiresUniqueEmail = SecUtility.GetBooleanValue(config, "requiresUniqueEmail", true);
this._maxInvalidPasswordAttempts = SecUtility.GetIntValue(config, "maxInvalidPasswordAttempts", 5, false, 0);
this._passwordAttemptWindow = SecUtility.GetIntValue(config, "passwordAttemptWindow", 10, false, 0);
this._minRequiredPasswordLength = SecUtility.GetIntValue(config, "minRequiredPasswordLength", 7, false, 128);
this._minRequiredNonAlphanumericCharacters = SecUtility.GetIntValue(config, "minRequiredNonalphanumericCharacters", 1, true, 128);
this._passwordStrengthRegularExpression = config["passwordStrengthRegularExpression"];
if (this._passwordStrengthRegularExpression != null)
{
this._passwordStrengthRegularExpression = this._passwordStrengthRegularExpression.Trim();
if (this._passwordStrengthRegularExpression.Length != 0)
{
try
{
new Regex(this._passwordStrengthRegularExpression);
}
catch (ArgumentException e)
{
throw new ProviderException(e.Message, e);
}
}
}
else
{
this._passwordStrengthRegularExpression = String.Empty;
}
this._applicationName = config["applicationName"];
if (String.IsNullOrEmpty(this._applicationName))
{
this._applicationName = SecUtility.GetDefaultAppName();
}
if (this._applicationName.Length > 255)
{
throw new ProviderException("Provider application name is too long, max length is 255.");
}
if (!ServiceLocator.ApplicationService.ApplicationExists(this._applicationName))
{
ServiceLocator.ApplicationService.CreateApplication(this._applicationName);
}
string strTemp = config["passwordFormat"];
if (strTemp == null)
{
strTemp = "Hashed";
}
switch (strTemp)
{
case "Clear":
this._passwordFormat = MembershipPasswordFormat.Clear;
break;
case "Encrypted":
this._passwordFormat = MembershipPasswordFormat.Encrypted;
break;
case "Hashed":
this._passwordFormat = MembershipPasswordFormat.Hashed;
break;
default:
throw new ProviderException("Bad password format.");
}
if (this._passwordFormat == MembershipPasswordFormat.Hashed && this._enablePasswordRetrieval)
{
throw new ProviderException("Provider cannot retrieve hashed password.");
}
config.Remove("applicationName");
config.Remove("enablePasswordRetrieval");
config.Remove("enablePasswordReset");
config.Remove("requiresQuestionAndAnswer");
config.Remove("requiresUniqueEmail");
config.Remove("maxInvalidPasswordAttempts");
config.Remove("passwordAttemptWindow");
config.Remove("passwordFormat");
config.Remove("name");
config.Remove("description");
config.Remove("minRequiredPasswordLength");
config.Remove("minRequiredNonalphanumericCharacters");
config.Remove("passwordStrengthRegularExpression");
if (config.Count > 0)
{
string attribUnrecognized = config.GetKey(0);
if (!String.IsNullOrEmpty(attribUnrecognized))
{
throw new ProviderException("Provider unrecognized attribute: " + attribUnrecognized);
}
}
}
/**//// <summary>
/// 修改用户密码
/// </summary>
/// <param name="username"></param>
/// <param name="oldPassword"></param>
/// <param name="newPassword"></param>
/// <returns></returns>
public override bool ChangePassword(string username, string oldPassword, string newPassword)
{
SecUtility.CheckParameter(ref username, true, true, true, 255, "username");
SecUtility.CheckParameter(ref oldPassword, true, true, false, 128, "oldPassword");
SecUtility.CheckParameter(ref newPassword, true, true, false, 128, "newPassword");
string salt;
MembershipPasswordFormat passwordFormat;
if (!CheckPassword(username, oldPassword, false, false, out salt, out passwordFormat))
{
return false;
}
if (newPassword.Length < this._minRequiredPasswordLength)
{
throw new ArgumentException("New Password too short.");
}
int nonAlphanumericCharacters = 0;
for (int i = 0; i < newPassword.Length; i++)
{
if (!char.IsLetterOrDigit(newPassword, i))
{
nonAlphanumericCharacters++;
}
}
if (nonAlphanumericCharacters < this._minRequiredNonAlphanumericCharacters)
{
throw new ArgumentException("Password need more non alpha numeric chars.");
}
if ((this._passwordStrengthRegularExpression.Length > 0) && !Regex.IsMatch(newPassword, this._passwordStrengthRegularExpression))
{
throw new ArgumentException("Password does not match regular expression.");
}
string pass = EncodePassword(newPassword, passwordFormat, salt);
if (pass.Length > 128)
{
throw new ArgumentException("Membership password too long.");
}
ValidatePasswordEventArgs args = new ValidatePasswordEventArgs(username, newPassword, false);
this.OnValidatingPassword(args);
if (args.Cancel)
{
if (args.FailureInformation != null)
{
throw args.FailureInformation;
}
throw new ArgumentException("Membership custom password validation failure.");
}
int status = ServiceLocator.UserService.UpdatePassword(this._applicationName, username, pass, salt, passwordFormat,
DateTime.UtcNow);
if (status != 0)
{
string errText = GetExceptionText(status);
if (IsStatusDueToBadPassword(status))
{
throw new MembershipPasswordException(errText);
}
throw new ProviderException(errText);
}
return true;
}
/**//// <summary>
/// 更新成员资格数据库中用户的密码提示问题和答案
/// </summary>
/// <param name="username"></param>
/// <param name="password"></param>
/// <param name="newPasswordQuestion"></param>
/// <param name="newPasswordAnswer"></param>
/// <returns></returns>
public override bool ChangePasswordQuestionAndAnswer(string username, string password,
string newPasswordQuestion, string newPasswordAnswer)
{
SecUtility.CheckParameter(ref username, true, true, true, 255, "username");
SecUtility.CheckParameter(ref password, true, true, false, 128, "password");
string salt;
MembershipPasswordFormat passwordFormat;
if (!CheckPassword(username, password, false, false, out salt, out passwordFormat))
{
return false;
}
SecUtility.CheckParameter(ref newPasswordQuestion, this.RequiresQuestionAndAnswer, this.RequiresQuestionAndAnswer, false, 255, "newPasswordQuestion");
if (newPasswordAnswer != null)
{
newPasswordAnswer = newPasswordAnswer.Trim();
}
SecUtility.CheckParameter(ref newPasswordAnswer, this.RequiresQuestionAndAnswer, this.RequiresQuestionAndAnswer, false, 128, "newPasswordAnswer");
string answer;
if (!String.IsNullOrEmpty(newPasswordAnswer))
{
answer = EncodePassword(newPasswordAnswer.ToLower(CultureInfo.InvariantCulture), passwordFormat, salt);
}
else
{
answer = newPasswordAnswer;
}
SecUtility.CheckParameter(ref answer, this._requiresQuestionAndAnswer, this._requiresQuestionAndAnswer, false, 128, "newPasswordAnswer");
int status = ServiceLocator.UserService.ChangePasswordQuestionAndAnswer(this._applicationName, username, newPasswordQuestion, answer);
if (status != 0)
{
throw new ProviderException(GetExceptionText(status));
}
return true;
}
using System.Collections.Generic;
using System.Text;
using System.Web.Security;
using System.Collections.Specialized;
using System.Configuration.Provider;
using System.Text.RegularExpressions;
using Guushuuse.SalaryPrj.Security.Service;
using System.Collections;
using System.Globalization;
using Guushuuse.SalaryPrj.Security.DomainModel;
using System.Security.Cryptography;
namespace Guushuuse.SalaryPrj.Security.Providers
{
/**//// <summary>
///管理数据库中 ASP.NET 应用程序的成员资格信息存储
/// </summary>
public class HibernateMembershipProvider : MembershipProvider
{
private string _applicationName;
private bool _enablePasswordReset;
private bool _enablePasswordRetrieval;
private int _maxInvalidPasswordAttempts;
private int _minRequiredNonAlphanumericCharacters;
private int _minRequiredPasswordLength;
private int _passwordAttemptWindow;
private MembershipPasswordFormat _passwordFormat;
private string _passwordStrengthRegularExpression;
private bool _requiresQuestionAndAnswer;
private bool _requiresUniqueEmail;
属性#region 属性
/**//// <summary>
/// 获取或设置要存储和检索其成员资格信息的应用程序的名称
/// </summary>
public override string ApplicationName
{
get
{
return _applicationName;
}
set
{
if (String.IsNullOrEmpty(value))
{
throw new ArgumentNullException("Provider application name not null.");
}
if (value.Length > 255)
{
throw new ProviderException("Provider application name too long.");
}
_applicationName = value;
}
}
/**//// <summary>
/// 获取一个值,指示成员资格提供程序是否配置为允许用户重置其密码
/// </summary>
public override bool EnablePasswordReset
{
get { return _enablePasswordReset; }
}
/**//// <summary>
/// 获取一个值,指示成员资格提供程序是否配置为允许用户检索其密码
/// </summary>
public override bool EnablePasswordRetrieval
{
get { return _enablePasswordRetrieval; }
}
/**//// <summary>
/// 获取锁定成员资格用户前允许的无效密码或无效密码提示问题答案尝试次数
/// </summary>
public override int MaxInvalidPasswordAttempts
{
get { return _maxInvalidPasswordAttempts; }
}
/**//// <summary>
/// 获取有效密码中必须包含的最少特殊字符数
/// </summary>
public override int MinRequiredNonAlphanumericCharacters
{
get { return _minRequiredNonAlphanumericCharacters; }
}
/**//// <summary>
/// 获取密码所要求的最小长度
/// </summary>
public override int MinRequiredPasswordLength
{
get { return _minRequiredPasswordLength; }
}
/**//// <summary>
/// 获取在锁定成员资格用户之前允许的最大无效密码或无效密码提示问题答案尝试次数的分钟数
/// </summary>
public override int PasswordAttemptWindow
{
get { return _passwordAttemptWindow; }
}
/**//// <summary>
/// 获取一个值,表示用于在成员资格数据库中存储密码的格式
/// </summary>
public override MembershipPasswordFormat PasswordFormat
{
get { return _passwordFormat; }
}
/**//// <summary>
/// 获取用于计算密码的正则表达式
/// </summary>
public override string PasswordStrengthRegularExpression
{
get { return _passwordStrengthRegularExpression; }
}
/**//// <summary>
/// 获取一个值,指示成员资格提供程序是否配置为要求用户在进行密码重置和检索时回答密码提示问题
/// </summary>
public override bool RequiresQuestionAndAnswer
{
get { return _requiresQuestionAndAnswer; }
}
/**//// <summary>
/// 获取一个值,指示成员资格提供程序是否配置为要求每个用户名具有唯一的电子邮件地址
/// </summary>
public override bool RequiresUniqueEmail
{
get { return _requiresUniqueEmail; }
}
#endregion 属性
方法#region 方法
/**//// <summary>
/// 使用 ASP.NET 应用程序配置文件中指定的属性值初始化成员资格提供程序
/// </summary>
/// <param name="name"></param>
/// <param name="config"></param>
public override void Initialize(string name, NameValueCollection config)
{
if (config == null)
{
throw new ArgumentNullException("config");
}
if (String.IsNullOrEmpty(name))
{
name = "HibernateMembershipProvider";
}
if (String.IsNullOrEmpty(config["description"]))
{
config.Remove("description");
config.Add("description", "GFC.Security Membership Provider");
}
base.Initialize(name, config);
this._enablePasswordRetrieval = SecUtility.GetBooleanValue(config, "enablePasswordRetrieval", false);
this._enablePasswordReset = SecUtility.GetBooleanValue(config, "enablePasswordReset", true);
this._requiresQuestionAndAnswer = SecUtility.GetBooleanValue(config, "requiresQuestionAndAnswer", true);
this._requiresUniqueEmail = SecUtility.GetBooleanValue(config, "requiresUniqueEmail", true);
this._maxInvalidPasswordAttempts = SecUtility.GetIntValue(config, "maxInvalidPasswordAttempts", 5, false, 0);
this._passwordAttemptWindow = SecUtility.GetIntValue(config, "passwordAttemptWindow", 10, false, 0);
this._minRequiredPasswordLength = SecUtility.GetIntValue(config, "minRequiredPasswordLength", 7, false, 128);
this._minRequiredNonAlphanumericCharacters = SecUtility.GetIntValue(config, "minRequiredNonalphanumericCharacters", 1, true, 128);
this._passwordStrengthRegularExpression = config["passwordStrengthRegularExpression"];
if (this._passwordStrengthRegularExpression != null)
{
this._passwordStrengthRegularExpression = this._passwordStrengthRegularExpression.Trim();
if (this._passwordStrengthRegularExpression.Length != 0)
{
try
{
new Regex(this._passwordStrengthRegularExpression);
}
catch (ArgumentException e)
{
throw new ProviderException(e.Message, e);
}
}
}
else
{
this._passwordStrengthRegularExpression = String.Empty;
}
this._applicationName = config["applicationName"];
if (String.IsNullOrEmpty(this._applicationName))
{
this._applicationName = SecUtility.GetDefaultAppName();
}
if (this._applicationName.Length > 255)
{
throw new ProviderException("Provider application name is too long, max length is 255.");
}
if (!ServiceLocator.ApplicationService.ApplicationExists(this._applicationName))
{
ServiceLocator.ApplicationService.CreateApplication(this._applicationName);
}
string strTemp = config["passwordFormat"];
if (strTemp == null)
{
strTemp = "Hashed";
}
switch (strTemp)
{
case "Clear":
this._passwordFormat = MembershipPasswordFormat.Clear;
break;
case "Encrypted":
this._passwordFormat = MembershipPasswordFormat.Encrypted;
break;
case "Hashed":
this._passwordFormat = MembershipPasswordFormat.Hashed;
break;
default:
throw new ProviderException("Bad password format.");
}
if (this._passwordFormat == MembershipPasswordFormat.Hashed && this._enablePasswordRetrieval)
{
throw new ProviderException("Provider cannot retrieve hashed password.");
}
config.Remove("applicationName");
config.Remove("enablePasswordRetrieval");
config.Remove("enablePasswordReset");
config.Remove("requiresQuestionAndAnswer");
config.Remove("requiresUniqueEmail");
config.Remove("maxInvalidPasswordAttempts");
config.Remove("passwordAttemptWindow");
config.Remove("passwordFormat");
config.Remove("name");
config.Remove("description");
config.Remove("minRequiredPasswordLength");
config.Remove("minRequiredNonalphanumericCharacters");
config.Remove("passwordStrengthRegularExpression");
if (config.Count > 0)
{
string attribUnrecognized = config.GetKey(0);
if (!String.IsNullOrEmpty(attribUnrecognized))
{
throw new ProviderException("Provider unrecognized attribute: " + attribUnrecognized);
}
}
}
/**//// <summary>
/// 修改用户密码
/// </summary>
/// <param name="username"></param>
/// <param name="oldPassword"></param>
/// <param name="newPassword"></param>
/// <returns></returns>
public override bool ChangePassword(string username, string oldPassword, string newPassword)
{
SecUtility.CheckParameter(ref username, true, true, true, 255, "username");
SecUtility.CheckParameter(ref oldPassword, true, true, false, 128, "oldPassword");
SecUtility.CheckParameter(ref newPassword, true, true, false, 128, "newPassword");
string salt;
MembershipPasswordFormat passwordFormat;
if (!CheckPassword(username, oldPassword, false, false, out salt, out passwordFormat))
{
return false;
}
if (newPassword.Length < this._minRequiredPasswordLength)
{
throw new ArgumentException("New Password too short.");
}
int nonAlphanumericCharacters = 0;
for (int i = 0; i < newPassword.Length; i++)
{
if (!char.IsLetterOrDigit(newPassword, i))
{
nonAlphanumericCharacters++;
}
}
if (nonAlphanumericCharacters < this._minRequiredNonAlphanumericCharacters)
{
throw new ArgumentException("Password need more non alpha numeric chars.");
}
if ((this._passwordStrengthRegularExpression.Length > 0) && !Regex.IsMatch(newPassword, this._passwordStrengthRegularExpression))
{
throw new ArgumentException("Password does not match regular expression.");
}
string pass = EncodePassword(newPassword, passwordFormat, salt);
if (pass.Length > 128)
{
throw new ArgumentException("Membership password too long.");
}
ValidatePasswordEventArgs args = new ValidatePasswordEventArgs(username, newPassword, false);
this.OnValidatingPassword(args);
if (args.Cancel)
{
if (args.FailureInformation != null)
{
throw args.FailureInformation;
}
throw new ArgumentException("Membership custom password validation failure.");
}
int status = ServiceLocator.UserService.UpdatePassword(this._applicationName, username, pass, salt, passwordFormat,
DateTime.UtcNow);
if (status != 0)
{
string errText = GetExceptionText(status);
if (IsStatusDueToBadPassword(status))
{
throw new MembershipPasswordException(errText);
}
throw new ProviderException(errText);
}
return true;
}
/**//// <summary>
/// 更新成员资格数据库中用户的密码提示问题和答案
/// </summary>
/// <param name="username"></param>
/// <param name="password"></param>
/// <param name="newPasswordQuestion"></param>
/// <param name="newPasswordAnswer"></param>
/// <returns></returns>
public override bool ChangePasswordQuestionAndAnswer(string username, string password,
string newPasswordQuestion, string newPasswordAnswer)
{
SecUtility.CheckParameter(ref username, true, true, true, 255, "username");
SecUtility.CheckParameter(ref password, true, true, false, 128, "password");
string salt;
MembershipPasswordFormat passwordFormat;
if (!CheckPassword(username, password, false, false, out salt, out passwordFormat))
{
return false;
}
SecUtility.CheckParameter(ref newPasswordQuestion, this.RequiresQuestionAndAnswer, this.RequiresQuestionAndAnswer, false, 255, "newPasswordQuestion");
if (newPasswordAnswer != null)
{
newPasswordAnswer = newPasswordAnswer.Trim();
}
SecUtility.CheckParameter(ref newPasswordAnswer, this.RequiresQuestionAndAnswer, this.RequiresQuestionAndAnswer, false, 128, "newPasswordAnswer");
string answer;
if (!String.IsNullOrEmpty(newPasswordAnswer))
{
answer = EncodePassword(newPasswordAnswer.ToLower(CultureInfo.InvariantCulture), passwordFormat, salt);
}
else
{
answer = newPasswordAnswer;
}
SecUtility.CheckParameter(ref answer, this._requiresQuestionAndAnswer, this._requiresQuestionAndAnswer, false, 128, "newPasswordAnswer");
int status = ServiceLocator.UserService.ChangePasswordQuestionAndAnswer(this._applicationName, username, newPasswordQuestion, answer);
if (status != 0)
{
throw new ProviderException(GetExceptionText(status));
}
return true;
}