.NET Framework Membership.ValidateUser(string username, string password) 深度剖析,以及动态配置实现
Membership 是System.Web.Security 用户登录验证的一个封装类静态类,提供 Membership.ValidateUser(string username, string password) 返回一个bool类型的等方法。
由于.NET之前不开源很多时候只知道大概的实现原理,比如调用这个类方法前需要在项目实现一个继承 MembershipProvider的类,该类提供了 public abstract bool ValidateUser(string username, string password);等抽象方法。
大概思路就是 Membership 封装 MembershipProvider派生类的初始化等操作来调用该类的具体实现。
先看看 Membership 类的几个关键代码
public static class Membership
{
public static MembershipProviderCollection Providers { get { Initialize(); return s_Providers; } }
public static MembershipProvider Provider
{
get
{
Initialize();
if (s_Provider == null)
{
throw new InvalidOperationException(SR.GetString(SR.Def_membership_provider_not_found));
}
return s_Provider;
}
}
private static void Initialize()
{
if (s_Initialized && s_InitializedDefaultProvider)
{
return;
}
if (s_InitializeException != null)
throw s_InitializeException;
if (HostingEnvironment.IsHosted)
HttpRuntime.CheckAspNetHostingPermission(AspNetHostingPermissionLevel.Low, SR.Feature_not_supported_at_this_level);
lock (s_lock)
{
if (s_Initialized && s_InitializedDefaultProvider)
{
return;
}
if (s_InitializeException != null)
throw s_InitializeException;
bool initializeGeneralSettings = !s_Initialized;
// the default provider can be initialized once the pre start init has happened (i.e. when compilation has begun)
// or if this is not even a hosted scenario
bool initializeDefaultProvider = !s_InitializedDefaultProvider &&
(!HostingEnvironment.IsHosted || BuildManager.PreStartInitStage == PreStartInitStage.AfterPreStartInit);
if (!initializeDefaultProvider && !initializeGeneralSettings)
{
return;
}
bool generalSettingsInitialized;
bool defaultProviderInitialized = false;
try
{
//通过web.config 配置实现初始化的配置参数。
RuntimeConfig appConfig = RuntimeConfig.GetAppConfig();
MembershipSection settings = appConfig.Membership;
generalSettingsInitialized = InitializeSettings(initializeGeneralSettings, appConfig, settings);
defaultProviderInitialized = InitializeDefaultProvider(initializeDefaultProvider, settings);
// VSO #265267 log warning in event log when using clear password and encrypted password in Membership provider
// VSO #433626 In order to minimize the behavior change, we are going to read the password format from the config settings only instead of getting from the provider class
// Also allow user to opt-out this feature.
if (AppSettings.LogMembershipPasswordFormatWarning)
{
CheckedPasswordFormat(settings);
}
}
catch (Exception e)
{
s_InitializeException = e;
throw;
}
// update this state only after the whole method completes to preserve the behavior where
// the system is uninitialized if any exceptions were thrown.
if (generalSettingsInitialized)
{
s_Initialized = true;
}
if (defaultProviderInitialized)
{
s_InitializedDefaultProvider = true;
}
}
}
private static bool InitializeSettings(bool initializeGeneralSettings, RuntimeConfig appConfig, MembershipSection settings)
{
if (!initializeGeneralSettings)
{
return false;
}
s_HashAlgorithmType = settings.HashAlgorithmType;
s_HashAlgorithmFromConfig = !string.IsNullOrEmpty(s_HashAlgorithmType);
if (!s_HashAlgorithmFromConfig)
{
// If no hash algorithm is specified, use the same as the "validation" in "<machineKey>".
// If the validation is "3DES", switch it to use "SHA1" instead.
MachineKeyValidation v = appConfig.MachineKey.Validation;
if (v != MachineKeyValidation.AES && v != MachineKeyValidation.TripleDES)
s_HashAlgorithmType = appConfig.MachineKey.ValidationAlgorithm;
else
s_HashAlgorithmType = "SHA1";
}
s_Providers = new MembershipProviderCollection();
if (HostingEnvironment.IsHosted)
{
ProvidersHelper.InstantiateProviders(settings.Providers, s_Providers, typeof(MembershipProvider));
}
else
{
foreach (ProviderSettings ps in settings.Providers)
{
Type t = Type.GetType(ps.Type, true, true);
if (!typeof(MembershipProvider).IsAssignableFrom(t))
throw new ArgumentException(SR.GetString(SR.Provider_must_implement_type, typeof(MembershipProvider).ToString()));
MembershipProvider provider = (MembershipProvider)Activator.CreateInstance(t);
NameValueCollection pars = ps.Parameters;
NameValueCollection cloneParams = new NameValueCollection(pars.Count, StringComparer.Ordinal);
foreach (string key in pars)
cloneParams[key] = pars[key];
provider.Initialize(ps.Name, cloneParams);
s_Providers.Add(provider);
}
}
TimeSpan timeWindow = settings.UserIsOnlineTimeWindow;
s_UserIsOnlineTimeWindow = (int)timeWindow.TotalMinutes;
return true;
}
private static bool InitializeDefaultProvider(bool initializeDefaultProvider, MembershipSection settings)
{
if (!initializeDefaultProvider)
{
return false;
}
s_Providers.SetReadOnly();
if (settings.DefaultProvider == null || s_Providers.Count < 1)
throw new ProviderException(SR.GetString(SR.Def_membership_provider_not_specified));
s_Provider = s_Providers[settings.DefaultProvider];
if (s_Provider == null)
{
throw new ConfigurationErrorsException(SR.GetString(SR.Def_membership_provider_not_found), settings.ElementInformation.Properties["defaultProvider"].Source, settings.ElementInformation.Properties["defaultProvider"].LineNumber);
}
return true;
}
}
//用户实现的派生类
public class SQLMembershipProvider: MembershipProvider
{
public SQLMembershipProvider()
{
}
public override bool ValidateUser(string username, string password)
{
//验证用户密码的具体用户级逻辑
}
}
webconfig 配置派生类参数
<membership defaultProvider="TestMembershipProvider">
<providers>
<clear />
<add connectionStringName="TestADConnectionString" connectionUsername="" connectionPassword="" attributeMapUsername="sAMAccountName" name="SQLMembershipProvider" type="Summer.Net.Security.SQLMembershipProvider,Summer.Net.Security" />
</providers>
</membership>
浙公网安备 33010602011771号