获取在ASP.NET Identity 2.0中分配了角色的用户列表

33

我有一个下拉列表框,其中列出了角色。我想获取具有该角色的用户列表。我的意思是“管理员”角色或“CanEdit”角色中的用户列表。这是我的代码:

public IQueryable<Microsoft.AspNet.Identity.EntityFramework.IdentityUser> 
  GetRolesToUsers([Control] string ddlRole)
{    
  //ddlRole returns role Id, based on this Id I want to list users

  var _db = new ApplicationDbContext();
  IQueryable<Microsoft.AspNet.Identity.EntityFramework.IdentityUser> query = _db.Users;

  if (ddlRole != null)
  {
    //query = query.Where(e => e.Claims == ddlRole.Value);  ???????              
  }

  return query;
}

请帮忙。

更新的代码(仍然有错误)

public List<IdentityUserRole> GetRolesToUsers([Control]string ddlRole)
{

  var roleManager = 
   new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(new ApplicationDbContext()));
  var users = roleManager.FindByName("Administrator").Users.ToList();
  return users;
}

错误:当ItemType设置为"Microsoft.AspNet.Identity.EntityFramework.IdentityUser"时,选择方法必须返回"IQueryable"或"IEnumerable"或"Microsoft.AspNet.Identity.EntityFramework.IdentityUser"之一。

我尝试了各种转换,但都没有帮助。

更新(已解决方案)

感谢chris544,他的想法帮助我解决了这个问题。以下是可行的解决方法:

public List<ApplicationUser> GetRolesToUsers([Control]string ddlRole)
{
  var context = new ApplicationDbContext();
  var users =
    context.Users.Where(x => x.Roles.Select(y => y.RoleId).Contains(ddlRole)).ToList();

  return users;
}

尝试使用Roles.GetUsersInRole(),您可以使用默认的角色提供程序API。 - Larry
@Larry,你是指[string[] u = Roles.GetUsersInRole(ddlRole)]还是[_roleManager.Roles.GetUsersInRole(ddlRole)]?第一个会产生“未启用角色管理器功能”的错误,而第二个则没有“GetUserInRole”的定义。我应该如何使用Roles.GetUsersInRole()? - Abhimanyu
你正在开发asp.net mvc 5吗?我目前正在开发4。进入任何操作方法并键入“Roles”,它位于“System.Web.Security”命名空间中。 - Larry
我正在使用ASP.NET 4.5和ASP.NET Identity 2.0。 - Abhimanyu
8个回答

41

虽然我不是专家,但是...

在Identity中似乎没有内置的功能可以做到这一点,我也无法从内置角色中使其工作(它似乎无法与基于声明的Identity一起使用)。

因此,最终我做了类似于以下的处理:

var users = context.Users        
    .Where(x => x.Roles.Select(y => y.Id).Contains(roleId))
    .ToList();
  • x.Roles.Select(y => y.Id) 获取用户 x 的所有角色 id 的列表
  • .Contains(roleId) 检查该 id 列表是否包含所需的 roleId

在 Identity 1.0 中没有内置此功能,但据我在网上阅读的信息,2.0 版本中应该会有。 - Abhimanyu
谢谢chris544,你的想法帮助我解决了这个问题。我更新了问题,相信它会帮助许多开发人员。 - Abhimanyu
寻找了一个小时左右,终于找到了一个简单的实现方法。谢谢! - Jacques Bronkhorst
1
如果角色的“Id”未知,则应首先使用“RoleManager”的实例。 - SepehrM
1
y.Id 应该改为 y.RoleId。 - Andrzej Martyna

13

我通过输入角色名称来查找该角色的信息,然后通过该角色的ID查找用户列表。

public List<ApplicationUser> GetUsersInRole(string roleName)
{
 var roleManager = 
  new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(new  ApplicationDbContext()));
 var role = roleManager.FindByName(roleName).Users.First();
 var usersInRole = 
  Users.Where(u => u.Roles.Select(r => r.RoleId).Contains(role.RoleId)).ToList();
 return usersInRole;
}

很棒的回答,Trieu。在我看来,提供了可重用的代码。简短、简洁,而且直截了当地运行! - clockwiseq
我发现@Trieu Doan在我的情况下是不正确的,有效的代码如下: var users = roleManager.FindByName(roleName).Users.Select(x => x.UserId); var usersInRole = Users.Where(u => users.Contains(u.Id)); - Bartek Wójcik

7
如果您想避免直接使用上下文,可以使用以下代码片段中的RoleManager
roleManager.FindByName("Administrator").Users

或者

roleManager.FindByName("CanEdit").Users

关于这个主题的简短讨论,请查看此线程

针对此问题的讨论请参考上述链接。

谢谢Horizon_Net,看起来我离解决方案很近了。请检查我的更新代码,它产生了错误。 - Abhimanyu
2
这将返回一个 IdentityUserRole 集合,而不是 ApplicationUser - SepehrM

4

有三种方法可以实现这一点。

在控制器中,可以按以下方式检查当前登录用户的角色:

  if(User.IsInRole("SysAdmin"))
        {

在控制器外部,您可以按以下方式检查特定用户是否属于角色:

 ApplicationUserManager UserManager = HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
        var roles = UserManager.GetRoles(userid);
        if (roles.Contains("SysAdmin"))
        {
        }

不要忘记添加命名空间。

using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.Owin;

出于某些原因,例如集成测试等,您可能需要直接使用 EF 查找用户的角色,如下所示:

string userId = User.Identity.GetUserId();
        ApplicationDbContext db = new ApplicationDbContext();
        var role = (from r in db.Roles where r.Name.Contains("Admin") select r).FirstOrDefault();
        var users = db.Users.Where(x => x.Roles.Select(y => y.RoleId).Contains(role.Id)).ToList();
        if (users.Find(x => x.Id == userId) != null)
        {
            // User is in the Admin Role
        }

希望它能有所帮助。
感谢 /dj @debug_mode

4
使用RoleManager可以为您提供以下解决方案:
if(roleManager.RoleExists("CanEdit"))
{
    var idsWithPermission = roleManager.FindByName("CanEdit").Users.Select(iur => iur.Id);
    var users = db.Users.Where(u => idsWithPermission.Contains(u.Id));
}

我很想知道这个解决方案与其他方案相比是更好还是更差。


我唯一的修改建议是在上面加一个 if 语句来检查角色是否存在。if(roleManager.RoleExists("CanEdit")) - Derek Hewitt
+1 前往 RoleManager(例如角色表)比进行多次 LINQ 查询最终产生大量 SQL 更好的快捷方式。 - Aaron Hudon

0

适用于我的代码如下所示:

  var users = roleManager.FindByName(roleName).Users.Select(x => x.UserId);
  var usersInRole = Users.Where(u => users.Contains(u.Id));

0

移除 .Email 并添加 UserName 或者其他已经添加到 ASPNetUsers 作为名称的字段。

private void AddAddminToMail(MailMessage message)
{
    var roles = db.Roles.Include(m => m.Users).Where(m => m.Name == "Admin").First();
    foreach (var user in roles.Users)
        {
            var id = user.UserId;
            var userEmail = db.Users.Find(id).Email;
            message.To.Add(userEmail);
        }      
}

0

由于像这样的位运算往往会影响性能,因此我尝试了在此处发布的其他答案并查看它们生成的SQL。这似乎是当前获取所有用户电子邮件地址的最高效方法。

public void SendEmailToUsersInRole(string roleName)
{
    MailMessage message = new MailMessage();
    ...

    using (var usersDB = new ApplicationDbContext())
    {
        var roleId = 
            usersDB.Roles.First(x => x.Name == roleName).Id;

        IQueryable<string> emailQuery =
            usersDB.Users.Where(x => x.Roles.Any(y => y.RoleId == roleId))
                         .Select(x => x.Email);

        foreach (string email in emailQuery)
        {
            message.Bcc.Add(new MailAddress(email));
        }
    }

    ...
}

执行的SQL如下所示:
SELECT TOP (1) 
    [Extent1].[Id] AS [Id], 
    [Extent1].[Name] AS [Name]
    FROM [dbo].[AspNetRoles] AS [Extent1]
    WHERE N'Reviewer' = [Extent1].[Name]

SELECT 
    [Extent1].[Email] AS [Email]
    FROM [dbo].[AspNetUsers] AS [Extent1]
    WHERE  EXISTS (SELECT 
        1 AS [C1]
        FROM [dbo].[AspNetUserRoles] AS [Extent2]
        WHERE ([Extent1].[Id] = [Extent2].[UserId]) AND ([Extent2].[RoleId] = @p__linq__0)
    )


-- p__linq__0: '3' (Type = String, Size = 4000)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接