【问题标题】:Set Access to dropdownlist items based on the User's Active Directory Group根据用户的 Active Directory 组设置对下拉列表项的访问权限
【发布时间】:2011-04-20 13:24:48
【问题描述】:

背景:我有一个 webForm 应用程序,它根据 Web 服务提供的信息在数据库中注册用户,自动生成随机密码和用户名,并通过电子邮件向用户发送一个链接以获取基于应用程序的应用程序选定的营销公司。

问题:

  • 如何仅让当前登录的用户组显示在 MarketingCo_DropDownList 下

每个允许访问系统的用户都将拥有至少一个由 web.config 定义的营销组的成员资格。例如,当前登录并属于位置“alg\ACOMP_user_BIG”下的 BIG 组的用户将只能在 Marketing Company 下拉列表中看到 BIG。当前登录并属于位于“alg\ACOMP_user_NIS”下的 NIS 组的用户将只能在 Marketing Company 下拉列表中看到 NIS。

这是前端的截图:

这是我的最佳猜测(位于 default.aspx.vb 中 Private Sub GetMarketingCompanies() 方法下):

    If InStr(WindowsIdentity.GetCurrent().Groups = "AMG", item.MarketingCompanyShort = "AMG", CompareMethod.Text) Then
            marketingCo.Items.Add(String.Format("{0} | {1}", item.MarketingCompanyShort, item.MarketingCompanyName))

            For Each item In ac1
                 marketingCo.Items.Add(String.Format("{0} | {1}", item.MarketingCompanyShort, item.MarketingCompanyName))
        Next
    Catch ex As Exception
        MsgBox(ex.Message)
    End Try

我一直在使用 Wrox's Windows Authentication Tutorial 的代码,但它对于我想要做的事情还不够彻底。

Web.config 文件(仅显示相关代码):

 <authentication mode="Windows"/>
   <authorization>            
    <allow users="alg\bmccarthy, alg\phoward" />               
    <allow roles="alg\ACOMP_user_Admin" />
    <allow roles="alg\ACOMP_user_AMG" />
    <allow roles="alg\ACOMP_user_BIG" />
    <allow roles="alg\ACOMP_user_NIS" />
    <allow roles="alg\ACOMP_user_GLA" />
    <allow roles="alg\ACOMP_user_PIP" />
    <allow roles="alg\ACOMP_user_PSM" />
    <allow roles="alg\ACOMP_user_PAM" />
    <allow roles="alg\ACOMP_user_ANN" />
    <allow roles="alg\ACOMP_user_AAM" />
    <allow roles="alg\ACOMP_user_MWM" /> 
    <allow roles="alg\ACOMP_user_GIM" />
    <deny users="*" />        
</authorization> 
   <bindings>
   <basicHttpBinding>
    <binding name="BasicHttpBinding_IAcompService" closeTimeout="00:01:00"
      openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
      allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
      maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
      messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
      useDefaultWebProxy="true">
      <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
        maxBytesPerRead="4096" maxNameTableCharCount="16384" />
      <security mode="None">
        <transport clientCredentialType="None" proxyCredentialType="None"
          realm="" />
          <message clientCredentialType="UserName" algorithmSuite="Default" />
        </security>
      </binding>
    </basicHttpBinding>
  </bindings>
  <client>
  <endpoint address="http://172.17.1.40/aCompService.svc" binding="basicHttpBinding"
    bindingConfiguration="BasicHttpBinding_IAcompService" contract="aComp_ServiceReference.IAcompService"
    name="BasicHttpBinding_IAcompService" />
  </client>
 </system.serviceModel>

带有 GetMarketingCompanies() 和 Page_Load() 方法的 default.aspx.vb 代码,应用程序从 Web 服务中检索 MarketingCompanies 并通过数组将其加载到下拉列表中:

Private Sub GetMarketingCompanies()
    Try
        Dim ac1 As Array
        ac1 = proxy.GetMarketingCompanyNames("acompUser", "acompPass!")


        ' If InStr(WindowsIdentity.GetCurrent().Groups = "AMG", item.MarketingCompanyShort = "AMG", CompareMethod.Text) Then
        '  marketingCo.Items.Add(String.Format("{0} | {1}", item.MarketingCompanyShort, item.MarketingCompanyName))

        ' if current user role="alg\ACOMP_user_BIG" display BIG MarketingCo.Item '
        ' if current user role="alg\ACOMP_user_NIS" display NIS MarketingCo.Item '
        ' if current user role="alg\ACOMP_user_GLA" display GLA MarketingCo.Item '
        ' if current user role="alg\ACOMP_user_PIP" display PIP MarketingCo.Item '
        ' if current user role="alg\ACOMP_user_PSM" display PSM MarketingCo.Item '
        ' if current user role="alg\ACOMP_user_PAM" display PAM MarketingCo.Item '
        ' if current user role="alg\ACOMP_user_ANN" display ANN MarketingCo.Item '
        ' if current user role="alg\ACOMP_user_AAM" display AAM MarketingCo.Item '
        ' if current user role="alg\ACOMP_user_MWM" display MWM MarketingCo.Item '
        ' if current user role="alg\ACOMP_user_GIM" display GIM MarketingCo.Item '

        ' if current user = alg\ACOMP_user_Admin display all marketing companies in drop down list '
        For Each item In ac1
            marketingCo.Items.Add(String.Format("{0} | {1}", item.MarketingCompanyShort, item.MarketingCompanyName))
        Next
    Catch ex As Exception
        MsgBox(ex.Message)
    End Try
End Sub

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load, Me.Load, Me.Load
    If Not lbCarriers.Items.Count > 0 Then
        GetCarriers()
        GetMarketingCompanies()
    End If
End Sub

定义marketingCo下拉列表的Default.aspx代码:

<table>
    <tr>
        <td class="style3">
            Marketing Co (auto-populated):
        </td>
        <td bgcolor="#ffffff" class="style8">
            <asp:DropDownList ID="marketingCo" runat="server" Height="23px" 
                Width="250px">
            </asp:DropDownList>
        </td>
    </tr>
        <td bgcolor="#ffffff" class="style6">
            <asp:Button ID="Send_Button" runat="server"  Text="Send Invitation" />
        </td>
    </tr>
</table>

Web 服务返回带有 MarketingCompanyShort 和 MarketingCompanyName 的字符串数组,这些字符串作为项目添加到下拉列表中 Web 服务 XSD 文件代码:

<xs:element name="ArrayOfMarketingCompany" type="tns:ArrayOfMarketingCompany" nillable="true"/>
<xs:complexType name="MarketingCompany">
    <xs:sequence>
        <xs:element name="MarketingCompanyId" type="xs:int" minOccurs="0"/>
        <xs:element name="MarketingCompanyName" type="xs:string" nillable="true" minOccurs="0"/>
        <xs:element name="MarketingCompanyShort" type="xs:string" nillable="true" minOccurs="0"/>
    </xs:sequence>
</xs:complexType>

感谢收看!

如果您有任何有用的链接或建议,我会给您投票!

【问题讨论】:

  • 您能否参数化您的服务调用以仅为特定组带回项目并将当前用户组作为参数发送?
  • @Subhash,我不确定你的意思,但我想我可以通过编辑 GetMarketingCompanies() 方法来做到这一点。
  • 是的,所以使用来自msdn.microsoft.com/en-us/library/… 的信息,您可以获取当前用户的组并更改您的 GetMarketingCompanies 方法以接受组作为参数并仅发送所需的信息。这也将节省您的带宽:)
  • @Subhash,虽然该代码示例有些帮助,但它并没有回答我的问题。我可以使用那一长页代码的哪一部分?您能否在答案中提供一些 VB.NET 代码,以便我对其进行投票?
  • 所以我是否使用这样的东西......如果 InStr(WindowsIdentity.GetCurrent.Groups = "AMG", item.MarketingCompanyShort = "AMG", CompareMethod.Text) 那么......它有一个错误。我不确定这个的正确语法。

标签: asp.net vb.net web-services active-directory windows-authentication


【解决方案1】:

我不确定我是否完全遵循;您是否将每个组名称与特定的营销公司相匹配。因为这个链接没有保存在 Active Directory 中的任何地方,只是通过匹配每个文本?

如果是这种情况,我认为您只想检查 windows itentitfy 返回的组。像这样的东西?

For Each UserGroup in WindowsIdentity.GetCurrent().Groups
  If UserGroup.Value = "AMG" Then
    Dim Company= ac1.Cast(Of [TypeOfItemHere]).Where(Function(ac) ac.MarketingCompanyShort = "AMG").FirstOrDefault
    If Company IsNot Nothing Then
      marketingCo.Items.Add(String.Format("{0} | {1}", Company.MarketingCompanyShort, Company.MarketingCompanyName))
    End If
  End If
Next

...对于其他组,依此类推。话虽这么说,最好将 WindowsIdentitiy.GetCurrent().Groups 传递给您的服务并在那里进行过滤。

【讨论】:

  • @Cwoo,感谢您的回复!每个允许访问系统的用户都将拥有至少一个由 web.config 定义的营销组的成员资格。例如,位于“alg\ACOMP_user_BIG”位置下的 BIG 组中的用户将只能在 Marketing Company 下拉列表中看到 BIG。位于“alg\ACOMP_user_NIS”下的 NIS 组中的用户将只能在 Marketing Company 下拉列表中看到 NIS。
  • 是的,每个组名都对应一个营销公司。我需要代码来检查当前登录用户的组,看看它们是否属于 alg\ACOMP_user_NIS、alg\ACOMP_user_BIG 等...在 alg 目录下有几个不同的组,如果我们把所有组都放上会更好在 alg\ACOMP\user_NIS 之类的目录下,或者参考和识别每个营销公司的最有效方法是什么?
  • 我不知道。如果您感兴趣的所有组都在同一个目录中,您可以使用 DirectoryEntry / DirectorySearcher 类来查找这些组。也许您可以考虑向这些组添加自定义属性,谷歌搜索表明这是可能的,但我没有尝试过的经验 (stackoverflow.com/questions/202736/…)。将“哪个组与哪个营销公司联系”信息放入数据库表中可能更容易(您的服务可以引用该表以返回过滤后的公司列表)?
  • @Cwoo,我在 VS2010 中的此代码中收到“ac1.Where”错误。我应该放什么? Intellisence 为我提供了 ac1 营销公司数组的以下选项 - getlength、getlowerbound、getupperbound、length、rank、setvalue。 “foreach”应该是带有空格的“For Each”。 For Each 循环应以 Next 子句结束
  • sigh ^^ 我在这里错了很多(对不起!),但至少我猜你正在努力?你可以让它与 sid 匹配,但它看起来很不雅观。 Google 建议将 Sid 转换为组名:bytes.com/topic/net/answers/430823-can-convert-sid-group-name
【解决方案2】:

IdentityReference.Value 返回当前用户的 SID(例如:S-1-5-32-544)而不是组名(例如:Acomp_user_BIG)。

您需要使用 IdentityReference.Translate 来转换 WindowsIdentiy.Groups 返回到 NTAccounts 的安全标识符 (SID)

以下代码将输出当前用户所属的所有组名:

Public ReadOnly Property Groups As IdentityReferenceCollection
    Get
        Dim identityReferenceCollection As IdentityReferenceCollection
        Dim identityReference As IdentityReference
        identityReferenceCollection = WindowsIdentity.GetCurrent().Groups
        Dim strGroupName As String
        Dim mcisloaded As Boolean

        ' Translate the current user's active directory groups 
        For Each identityReference In identityReferenceCollection
            Dim mktGroup As IdentityReference = identityReference.Translate(GetType(NTAccount))
            ' MsgBox(mktGroup.Value)

            strGroupName = mktGroup.Value.ToString
         Next    

    End Get
End Property

【讨论】:

  • 这是一个属性。属性的 Get 方法必须返回一个值。在 End Get 之前输入 Return irc。
  • 谢谢! @Cwoo,我在哪里/如何检查 System.Diagnostics.Debug.Listeners 集合中的跟踪侦听器?我正在尝试查看为活动目录组返回的值。我添加了一个 MsgBox(account.Value) 并且没有 msgBox 出现
  • 如果您直接在 Web 服务器上而不是通过 Visual Studio 运行代码,您将不会看到消息框。我建议只放置一些断点并通过 Visual Studio 运行您的应用程序,而不是这种猜测工作!话虽如此,您也可以使用类似的东西查看托管的调试输出:tanzimsaqib.com/blog/105/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-10-14
  • 1970-01-01
  • 1970-01-01
  • 2023-04-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多