【问题标题】:Custom role provider IsInRole fails?自定义角色提供程序 IsInRole 失败?
【发布时间】:2014-02-03 13:55:06
【问题描述】:

我创建了一个简单的角色提供程序。 (所以形成身份验证)。

放置在页面上的标准内置 asp.net 登录控件可以正常工作。

我正在尝试确定角色成员资格的标准“测试”为何会失败。

到目前为止我有这个:

Roles.Provider.IsUserInRole(Membership.GetUser.UserName, "Portal") 返回 true

Roles.IsUserInRole(Membership.GetUser.UserName, "Portal") 返回 false

为什么第二种格式会失败? (注意下面的 IsInRole 代码是由上面的 BOTH 调用的!!)。

User.IsInRole("Portal") 返回 false。

那么,在 3 个示例中,只有一个有效?

有人对为什么 User.IsInRole() 不起作用有任何建议吗?

请注意,User.IsInRole() 出于某种原因不会调用以下例程,但上面的两个代码会。

Public Overrides Function IsUserInRole(username As String, roleName As String) As Boolean

    Dim rst As DataTable
    Dim strSql As String
    MsgBox("Is user in Role test")
    strSql = "SELECT Email, RoleName FROM  dbo_ContactName " & _
             "LEFT JOIN Web_UsersInRoles ON Web_usersInRoles.User_ID = dbo_ContactName.Id " & _
             "LEFT JOIN Web_Roles on Web_Roles.ID = Web_UsersInRoles.Role_ID " & _
             "WHERE Email = '" & username & "' and RoleName = '" & roleName & "'"

    rst = Myrst(strSql)

    If rst.Rows.Count > 0 Then
        Return True
    Else
        Return False
    End If

End Function

请注意,最令人困惑的是:

Roles.IsUserInRole(Membership.GetUser.UserName, "Portal") 返回 false

我已验证上述内容会导致我的自定义代码运行,但始终返回 false。

事实上,如果我对上面的例程进行硬编码以返回“true”,那么上面的#2 仍然调用我的代码并且仍然返回 false!!!

这么大的问题: 即使对上述例程进行硬编码以始终返回 true,为什么这种格式会失败?

Roles.IsUserInRole(Membership.GetUser.UserName, "Portal")

更糟糕的是,为什么会失败?

User.IsInRole("Portal") 再次总是返回 false。

那么我应该寻找哪些设置才能使 2 和 3 工作?

总结:

1 - Roles.Provider.IsUserInRole(Membership.GetUser.UserName, "Portal") 返回 true

2 - Roles.IsUserInRole(Membership.GetUser.UserName, "Portal") 返回 false

3 - User.IsInRole("Portal") 返回 false

4 - User.Identity.Name 返回正确的登录用户 kallal@msn.com

我还可以从上面的#3 中验证从不调用 IsUserInRole 代码。这包括在清除浏览器缓存之后。

快速 BinGoolge 显示,很多人发现 User.IsInRole() 在采用自定义角色提供程序时停止工作。这里一定有一些“重大”问题在编写导致失败的自定义角色提供程序时被遗漏。

非常感谢有关如何使以上 2 或 3 个选项起作用的链接或建议。

使用 Visual Studio 2013,并使用 vb.net(框架 4.5)创建标准 asp.net 网站

编辑: 作为跟进,我的所有角色功能都有效。

例如: Roles.GetAllRoles() - 这有效(返回所有角色正确)

Roles.GetRolesForUser() - this works, retruns  all roles for CURRENT user

Roles.GetUserInRole("Portal") - this works, returns all users in role group "portal"

不工作:

User.IsInRole("Portal") - as noted 1000's of posts on internet have this issue!

Roles.IsUserInRole(Membership.GetUser.UserName, "Portal")

以下是我未包含在原始帖子中的其他子项:

Public Overrides Function GetUsersInRole(roleName As String) As String()

    Dim rst As DataTable
    Dim i As Integer
    Dim a As New List(Of String)
    Dim strSql As String
    MsgBox("get users in role code")
    strSql = "SELECT Email, RoleName FROM  dbo_ContactName " & _
             "LEFT JOIN Web_UsersInRoles ON Web_usersInRoles.User_ID = dbo_ContactName.Id " & _
             "LEFT JOIN Web_Roles on Web_Roles.ID = Web_UsersInRoles.Role_ID " & _
             "WHERE RoleName = '" & roleName & "' " & _
             "ORDER BY Web_Roles.RoleName"
    rst = Myrst(strSql)

    For i = 0 To rst.Rows.Count - 1
        a.Add(rst.Rows(i).ItemArray(0).ToString)
    Next

    Return a.ToArray

End Function

Public Overrides Function GetRolesForUser(username As String) As String()

    Dim rst As DataTable
    Dim i As Integer
    Dim a As New List(Of String)
    Dim strSql As String

    strSql = "SELECT Email, RoleName FROM  dbo_ContactName " & _
             "LEFT JOIN Web_UsersInRoles ON Web_usersInRoles.User_ID = dbo_ContactName.Id " & _
             "LEFT JOIN Web_Roles on Web_Roles.ID = Web_UsersInRoles.Role_ID " & _
             "WHERE Email = '" & username & "' " & _
             "ORDER BY Web_Roles.RoleName"

    rst = Myrst(strSql)

    For i = 0 To rst.Rows.Count - 1
        a.Add(rst.Rows(i).ItemArray(1).ToString)
    Next

    Return a.ToArray

End Function

Public Overrides Function GetAllRoles() As String()

    Dim rst As DataTable
    Dim i As Integer
    Dim a As New List(Of String)

    rst = Myrst("select RoleName from Web_Roles order by RoleName")

    For i = 0 To rst.Rows.Count - 1
        a.Add(rst.Rows(i).ItemArray(0).ToString)
    Next

    Return a.ToArray

End Function

以上所有功能都可以使用。

问题仍然存在:

我们如何连接到启用 User.IsInRole() 的使用。这不起作用。

总之:

Roles.GetRolesForUser    - returns "current" roles for user - works fine

Roles.GetUsersInRole("Portal")  - works fine

Roles.GetAllRoles() - works fine.

User.IsInRole() - BROKEN!

更多总结:这是一些带有结果输出的代码:

    Debug.WriteLine(Roles.Provider.IsUserInRole(Membership.GetUser.UserName, "Portal"))

    Debug.WriteLine(Roles.IsUserInRole(Membership.GetUser.UserName, "Portal"))

    Debug.WriteLine(User.Identity.Name)

    Debug.WriteLine(User.Identity.IsAuthenticated)

    Debug.WriteLine(User.IsInRole("Portal"))

输出:

Roles.Provider.IsUserInRole  = True
Roles.IsUserInRole = False
User.Identity.Name = kallal@msn.com
User.Identity.IsAuthenticated = True
User.IsInRole("Portal")  = False   < -- still broken!!!

【问题讨论】:

  • 如前所述,我测试了许多在线示例,但都失败了!

标签: asp.net vb.net


【解决方案1】:

您需要在您的自定义提供程序中实现GetRolesForUser。

当您在 ASP.NET 应用程序中为当前用户调用Roles.IsUserInRole时,它将调用System.Web.Security.RolePrincipal.IsUserInRole。

RolePrincipal.IsUserInRole 将在首次访问时调用角色提供者的GetRolesForUser 方法,并在内部缓存角色列表。它从不真正调用提供者的IsUserInRole 方法。

令人困惑的是,当您在 WCF 应用程序中使用 ASP.NET 角色时,它的工作方式有所不同 (principalPermissionMode="UseAspNetRoles")。在这种情况下,它不使用System.Web.Security.RolePrincipal 类,而是使用内部类System.ServiceModel.Security.RoleProviderPrincipal。

RoleProviderPrincipal.IsUserInRole 将调用 Role Provider 的 IsUserInRole 方法,并且不会尝试缓存当前用户的角色列表。

两种不同的实现具有不同的性能特征。

  • ASP.NET 方法(GetRolesForUser 然后在内部缓存角色)意味着即使在处理请求期间多次调用 IsUserInRole,也只有一次调用提供程序。但是对于某些提供商(例如WindowsTokenRoleProvider),getting the list of all roles can be expensive, resulting in poor performance。

  • WCF 方法(每次调用提供程序的 IsUserInRole 方法)可能会导致在处理单个请求期间多次调用提供程序。但是,除非明确请求,否则永远不会检索当前用户的完整角色列表,这可以为 WindowsTokenRoleProvider 等提供者提供更好的性能,因为这种检索成本很高。

【讨论】:

  • 我有所有的覆盖存根。我已经在帖子中添加了额外的存根。他们工作得很好。如果您在 Internet 上获取 1000 个示例并设置标准角色提供程序,那么对于我能够测试的所有示例,User.IsInRole 都会失败。所以 100 或 10,000 人尝试此操作将有相同的故障。一个简单的问题是如何连接它以便 User.IsInRole() 可以工作。
  • 你在哪里调用 User.IsInRole?直到用户通过身份验证并且您已从登录页面重定向后,它才会起作用。您还应该检查您的 web.config 中是否有“roleManager enabled='true'”。
  • 是的,我在新页面上。是的,当然角色管理器设置为启用,因为所有其他角色管理器功能都有效。我刚刚编辑了帖子,最后我有一系列 debug.writeline 来显示输出。失败的是 User.IsInRole()。正如我所说,我发现 1000 多个帖子都有同样的问题——这里遗漏了一些重要的细节,我只是不确定那个“丢失”的细节是什么,但这是常见的问题和问题——社区没有却想出了一个共同的答案。
  • 作为后续,这里是一个示例角色提供程序 - 它再次像我的代码一样工作,并且 IsInRole() 再次失败,就像我的代码一样。 codeproject.com/Articles/27955/… 也许我应该问是否有人可以找到 IsInRole() 工作的任何示例代码。
  • @AlbertD.Kallal - 我的建议是调试和检查 HttpContext.Current.User。它应该是 RolePrincipal 类型并具有预期的用户名。如果不是,也许有一些代码将其设置为其他内容(例如在 global.asax 中)。或者,当您不在请求的上下文中时(HttpContext.Current 为空),您可能正在调用它。如果这没有帮助,请创建一个展示问题行为的最小示例项目。如果您可以在某处提供它,我将很乐意查看它。无论如何,我经常使用自定义 RoleProvider 没有问题。
【解决方案2】:

这里概述了这个难以捉摸的问题的解决方案:

HttpContext.Current.User.IsInRole not working

发帖人的回答和跟进包含在 cmets 部分。

建议的解决方案是在角色名称上放置一个 trim()。完成后代码开始工作!

角色名称有一个尾随空格,作为远景,我在为用户加载角色的代码上进行了修剪,果然代码开始工作了。现在提供角色的原始数据已经被修剪,那么有问题的 in 代码现在可以工作了。

我不能相信这个解决方案,但这个问题和问题的链接包含在上面。

因此,由于某些角色名称的尾随空白,此代码(和其他测试的代码)失败了。

最有趣的是

Roles.Provider.IsUserInRole(Membership.GetUser.UserName, "Portal")

以上工作!尾随空格

Roles.IsUserInRole(Membership.GetUser.UserName, "Portal")

以上不适用于尾随空格

User.IsInRole("Portal")

以上不适用于尾随空格。

所以这里的巨大提示是 Roles.Provider.IsUserInRole(Membership.GetUser.UserName, "Portal") 确实有效!如果其他人都失败了,那么 REST 保证你的角色名称中有杂散空格。

移除杂散空间后,上述所有示例在所有情况下现在都可以正常工作。

【讨论】:

    【解决方案3】:

    感谢 Joe ->“User.IsInRole”在用户通过身份验证后才会起作用

    为我解决了 display-what-when 的问题!在_Layout.cshtml

     @if (HttpContext.Current.User.Identity.IsAuthenticated)
       {
        if (HttpContext.Current.User.IsInRole("Manager"))
          { 
           @Html.Partial("_ManageNav")
          }
        if (HttpContext.Current.User.IsInRole("Administrator"))
          { 
           @Html.Partial("_ManageNav")
          }
       }
    

    如果用户被分配了经理或管理员角色,则仅显示“_ManageNav”

    不适用于组合字符串(“经理,管理员”)

    不适用于组合字符串(“Manager”、“Administrator”)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-05-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多