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

  

posted on 2020-03-15 18:19  迎着风追赶  阅读(593)  评论(0编辑  收藏  举报

导航