【问题标题】:Administer asp.net website (create new users, assign users to roles, etc.) from a windows app从 Windows 应用程序管理 asp.net 网站(创建新用户、为用户分配角色等)
【发布时间】:2010-02-12 21:45:31
【问题描述】:

我有一个使用基于表单的身份验证的 asp.net Web 应用程序、一个 SqlMembershipProvider(使用加密的密码格式)和一个 SqlRoleProvider。我需要知道是否可以从 Windows 应用程序管理用户(创建新用户、将他们分配给角色等)——这些权力不需要网络应用程序本身的任何管理功能。

这是来自 web.config 的成员资格提供者定义:

<membership defaultProvider="MyProvider">
  <providers>
    <add name="MyProvider"
         type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
         connectionStringName="MyConnectionString"
         enablePasswordRetrieval="false"
         enablePasswordReset="true"
         requiresQuestionAndAnswer="true"
         applicationName="/MyWebApp"
         requiresUniqueEmail="true"
         passwordFormat="Encrypted"
         maxInvalidPasswordAttempts="5"
         minRequiredPasswordLength="7"
         minRequiredNonalphanumericCharacters="1"
         passwordAttemptWindow="10"
         passwordStrengthRegularExpression=""/>
  </providers>
</membership>

以及角色管理器定义:

<roleManager enabled="true" defaultProvider="MyRoleManager">
  <providers>
    <add name="MyRoleManager"
         type="System.Web.Security.SqlRoleProvider"
         connectionStringName="MyConnectionString"
         applicationName="/MyWebApp" />
  </providers>
</roleManager>

这是 machineKey 定义(能够使用加密密码所必需的):

<machineKey
    validationKey="BC50A82A6AF6A015C34C7946D29B817C00F04D2AB10BC2128D1E2433D0E365E426E57337CECAE9A0681A2C736B9779B42F75D60F09F142C60E9E0E8F9840DB46"
      decryptionKey="122035576C5476DCD8F3611954C837CDA5FE33BCDBBF23F7"
      validation="SHA1"
      decryption="AES"/>

所以,很明显,我有一个 Sql Server 数据库,其中包含 Web 应用程序的用户和角色。我想创建一个引用 Web 应用程序集的单独 Windows 应用程序,并使用配置的 MembershipProvider、RoleProvider 和 machineKey 来创建用户、将用户分配给角色等。如果这不可能,我可以复制配置设置Windows 应用程序中的 web.config。但我也不知道该怎么做。

我认为这是可能的吗?我已经尝试在谷歌上搜索解决方案,但信噪比非常糟糕。

【问题讨论】:

    标签: c# .net asp.net vb.net winforms


    【解决方案1】:

    一些选项:

    • 您可以使用Web Site Administration Tool,这不是 基于 Windows 窗体,但不是其中的一部分 您的 Web 应用程序。它来了 与 Visual Studio 并可以 通过单击 ASP.NET 访问 解决方案中的配置图标 探索者。
    • 可以直接操作 a 使用的提供者数据库 来自 Windows 的 SqlMembershipProvider 表单应用程序,但您可能必须是 小心不要弄坏东西。
    • 如果您要创建自定义 会员提供者,你会在 控制成员资格和角色的方式 数据被持久化。如果你这样做了 你可以创建一个可重用的库 可用于 Web 应用程序和 一个 Windows 窗体应用程序。

    我不认为尝试从 Windows 窗体应用程序中使用 SqlMembershipProvider 是一种实用的方法。

    【讨论】:

    • 它可以在 VS 中使用,但是您可以在生产环境中使用网站管理工具吗?
    • @fre0n:技术上是的,但这并不简单。此处描述:forums.asp.net/p/932674/1155428.aspx 我会研究我提到的其他选项。
    • 这是一个很好的建议...您最好轻松地做到这一点。否则,您最好创建自己的成员资格和角色提供者。
    【解决方案2】:

    我想出了一个解决方案,基于其他答案(谁都得到了 +1)和some othersites out there

    首先,我创建了应用程序配置文件 (app.config)。它准确地反映了 web 应用程序的 web.config 中的内容,但连接字符串的处理方式除外:

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
    
      <configSections>
        <section name="connectionStrings" type="System.Configuration.ConnectionStringsSection, System.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" requirePermission="false" />
      </configSections>
    
      <connectionStrings>
        <add name="MyConnectionString"
             connectionString ="SERVER=abc;UID=def;PWD=hij;Initial Catalog=klm;MultipleActiveResultsets=True"/>
      </connectionStrings>
    
      <system.web>
    
        <membership defaultProvider="MySqlMembershipProvider">
          <providers>
            <add name="MySqlMembershipProvider"
                 type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
                 connectionStringName="MyConnectionString"
                 enablePasswordRetrieval="false"
                 enablePasswordReset="true"
                 requiresQuestionAndAnswer="true"
                 applicationName="/MyWebApp"
                 requiresUniqueEmail="true"
                 passwordFormat="Encrypted"
                 maxInvalidPasswordAttempts="5"
                 minRequiredPasswordLength="7"
                 minRequiredNonalphanumericCharacters="1"
                 passwordAttemptWindow="10"
                 passwordStrengthRegularExpression=""/>
          </providers>
        </membership>
    
        <roleManager enabled="true" defaultProvider="MySqlRoleManager">
          <providers>
            <add name="MySqlRoleManager"
                 type="System.Web.Security.SqlRoleProvider"
                 connectionStringName="MyConnectionString"
                 applicationName="/MyWebApp" />
          </providers>
        </roleManager>
    
        <machineKey
          validationKey="BC50A82A6AF6A015C34C7946D29B817C00F04D2AB10BC2128D1E2433D0E365E426E57337CECAE9A0681A2C736B9779B42F75D60F09F142C60E9E0E8F9840DB46"
          decryptionKey="122035576C5476DCD8F3611954C837CDA5FE33BCDBBF23F7"
          validation="SHA1"
          decryption="AES"/>
      </system.web>
    
    </configuration>
    

    然后我创建了一个帮助类,它提供对两个单例的访问:MembershipProviderRoleProvider。事实证明这比我想象的要容易,一旦我知道该怎么做:

    using System.Configuration;
    using System.Reflection;
    using System.Web.Security;
    
    namespace WebAdminViaWindows
    {
        internal static class Provider
        {
            private static readonly string assemblyFilePath = Assembly.GetExecutingAssembly().Location;
    
            static Provider()
            {
                Membership = CreateMembershipProvider();
                Role = CreateRoleProvider();
            }
    
            public static MembershipProvider Membership { get; private set; }
            public static RoleProvider Role { get; private set; }
    
            private static MembershipProvider CreateMembershipProvider()
            {
                var config = ConfigurationManager.OpenExeConfiguration(assemblyFilePath);
    
                var systemWebGroup = config.SectionGroups["system.web"];
                if (systemWebGroup == null)
                {
                    throw new ConfigurationErrorsException("system.web group not found in configuration");
                }
    
                var membershipSection = systemWebGroup.Sections["membership"];
                if (membershipSection == null)
                {
                    throw new ConfigurationErrorsException("membership section not found in system.web group");
                }
    
                var defaultProviderProperty = membershipSection.ElementInformation.Properties["defaultProvider"];
                if (defaultProviderProperty == null)
                {
                    throw new ConfigurationErrorsException("defaultProvider property not found in membership section");
                }
    
                var defaultProviderName = defaultProviderProperty.Value as string;
                if (defaultProviderName == null)
                {
                    throw new ConfigurationErrorsException("defaultProvider property is not a string value");
                }
    
                var providersProperty = membershipSection.ElementInformation.Properties["providers"];
                if (providersProperty == null)
                {
                    throw new ConfigurationErrorsException("providers property not found in membership section");
                }
    
                var providerCollection = providersProperty.Value as ProviderSettingsCollection;
                if (providerCollection == null)
                {
                    throw new ConfigurationErrorsException("providers property is not an instance of ProviderSettingsCollection");
                }
    
                ProviderSettings membershipProviderSettings = null;
    
                foreach (ProviderSettings providerSetting in providerCollection)
                {
                    if (providerSetting.Name == defaultProviderName)
                    {
                        membershipProviderSettings = providerSetting;
                    }
                }
    
                if (membershipProviderSettings == null)
                {
                    if (providerCollection.Count > 0)
                    {
                        membershipProviderSettings = providerCollection[0];
                    }
                    else
                    {
                        throw new ConfigurationErrorsException("No providers found in configuration");
                    }
                }
    
                var provider = new SqlMembershipProvider();
                provider.Initialize("MySqlMembershipProvider", membershipProviderSettings.Parameters);
                return provider;
            }
    
            private static RoleProvider CreateRoleProvider()
            {
                var config = ConfigurationManager.OpenExeConfiguration(assemblyFilePath);
    
                var systemWebGroup = config.SectionGroups["system.web"];
                if (systemWebGroup == null)
                {
                    throw new ConfigurationErrorsException("system.web group not found in configuration");
                }
    
                var roleManagerSection = systemWebGroup.Sections["roleManager"];
                if (roleManagerSection == null)
                {
                    throw new ConfigurationErrorsException("roleManager section not found in system.web group");
                }
    
                var defaultProviderProperty = roleManagerSection.ElementInformation.Properties["defaultProvider"];
                if (defaultProviderProperty == null)
                {
                    throw new ConfigurationErrorsException("defaultProvider property not found in roleManager section");
                }
    
                var defaultProviderName = defaultProviderProperty.Value as string;
                if (defaultProviderName == null)
                {
                    throw new ConfigurationErrorsException("defaultProvider property is not a string value");
                }
    
                var providersProperty = roleManagerSection.ElementInformation.Properties["providers"];
                if (providersProperty == null)
                {
                    throw new ConfigurationErrorsException("providers property not found in roleManagerSection section");
                }
    
                var providerCollection = providersProperty.Value as ProviderSettingsCollection;
                if (providerCollection == null)
                {
                    throw new ConfigurationErrorsException("providers property is not an instance of ProviderSettingsCollection");
                }
    
                ProviderSettings roleProviderSettings = null;
    
                foreach (ProviderSettings providerSetting in providerCollection)
                {
                    if (providerSetting.Name == defaultProviderName)
                    {
                        roleProviderSettings = providerSetting;
                    }
                }
    
                if (roleProviderSettings == null)
                {
                    if (providerCollection.Count > 0)
                    {
                        roleProviderSettings = providerCollection[0];
                    }
                    else
                    {
                        throw new ConfigurationErrorsException("No providers found in configuration");
                    }
                }
    
                var provider = new SqlRoleProvider();
                provider.Initialize("MySqlRoleManager", roleProviderSettings.Parameters);
                return provider;
            }
        }
    }
    

    此时所需要做的就是访问Provider 类的MembershipRole 属性。例如,以下打印出前 10 个用户及其角色:

    int total;
    foreach (MembershipUser user in Provider.Membership.GetAllUsers(0, 10, out total))
    {
        var sb = new StringBuilder();
        sb.AppendLine(user.UserName);
        foreach (var role in Provider.Role.GetRolesForUser(user.UserName))
        {
            sb.AppendLine("\t" + role);
        }
    
        Console.WriteLine(sb.ToString());
    }
    

    【讨论】:

    • 令人印象深刻。没想到会这么简单。
    【解决方案3】:

    我不确定这里的“最佳实践”是什么,但应该工作的简单方法就是这样。

    • 制作一个新的 windows 应用
    • 添加应用程序配置文件 (app.config)
    • 将适当的设置复制到 app.config(上面的设置 ^)
    • 添加对 System.Web 的引用
    • 然后从您的网络应用程序中复制代码 使用上述设置 连接数据库

    这应该可以满足您的需求。

    【讨论】:

    • 我可以实例化一个 SqlMembershipProvider 和一个 SqlRoleProvider 并设置几乎所有必要的属性,但是如何给它们一个连接字符串呢?我将如何为 SqlMembershipProvider 提供验证和解密密钥?
    • 根据msdn.microsoft.com/en-us/library/…,没有设置SqlMembershipProvider的连接字符串的属性或方法。
    • 您应该能够以与在 Web 应用程序中相同的方式完成所有这些操作。我假设您在您的网络应用程序中使用类似的代码让用户登录?
    • 在网络应用程序中,初始化都是自动完成的。您永远不必手动调用SqlMembershipProviderInitialize 方法。另外,我使用的是登录控件,所以我什至从未接触过SqlMembershipProvider
    猜你喜欢
    • 2012-07-02
    • 2013-01-02
    • 2012-02-02
    • 2014-05-05
    • 1970-01-01
    • 1970-01-01
    • 2020-10-16
    • 2016-01-30
    • 1970-01-01
    相关资源
    最近更新 更多