如何从 ASP.NET Identity 2 获取用户的子集

How to get a subset of Users from ASP.NET Identity 2

使用稍微修改过的默认 ASP.NET MVC 5 模板(带有个人帐户),我试图根据中介 table 获取一部分用户。我已经建立了一个管理 UI 可以 return 所有用户的列表,但现在我需要根据当前登录用户的访问权限来限制用户集 returned定义在中介 table.

基本上,每个用户都可以访问 1 个或多个诊所,因此他们可以访问的每个诊所都有一个记录。

如果当前登录的用户属于给定角色(例如,"Clinic Admin"),那么他们应该能够检索属于 any[= 的任何用户的列表39=] 他们可以访问的诊所。

谁能帮我指明正确的方向?这是我的第一个 Anything.NET 应用程序,所以请像我五岁一样随意解释。 :-)

提前感谢您提供的任何帮助。

附加信息:

  • Visual Studio 2013 更新 5
  • Entity Framework 6
  • MS SQL 服务器 2008 R2

这里是中介table的class(ClinicUser):

[Table("clinic_users")]
public class ClinicUser
{
    [Key]
    public virtual ApplicationUser ApplicationUsers { get; set; }

    [Required]
    public string Id { get; set; }

    [Required]
    public System.Guid provider_id { get; set; }

    [Required]
    public System.Guid health_system_id { get; set; }

    [Required]
    public System.Guid clinic_id { get; set; }
}

这是我的 ApplicationUser class:

public class ApplicationUser : IdentityUser
{
    public string FirstName { get; set; }

    public string LastName { get; set; }

    public string FullName
    {
        get { return FirstName + " " + LastName; }
    }

    [ForeignKey("ClinicUsers")]
    public override string Id
    {
        get
        {
            return base.Id;
        }
        set
        {
            base.Id = value;
        }
    }

    public virtual ClinicUser ClinicUsers { get; set; }

    public IEnumerable<SelectListItem> RolesList { get; set; }

    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
    {
        // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
        var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
        // Add custom user claims here
        userIdentity.AddClaims(ClinicClaimsProvider.GetClaims(userIdentity));
        return userIdentity;
    }
}

如果不清楚,我真正想做的是将 ApplicationUsers 列表缩小到 return 只有我根据我们拥有的诊所可以访问的用户列表有共同点。

如果我把它写成一个 SQL 查询,这将是完成我想要的东西的一种方法(我似乎无法用 LINQ 完全得到我想要的东西):

SELECT *
FROM AspNetUsers au
WHERE Id IN (
    SELECT Id
    FROM clinic_users
    WHERE clinic_id IN (
            SELECT clinic_id
            FROM clinic_users
            WHERE Id = 'CurrentUserId'
            )
    )

我不久前解决了这个问题,但我想我最好回到这里并用答案更新我的问题,以防这可能对其他人有所帮助。

我相应地更新了我的 Clinic 和 ClinicUser classes:

Clinic.cs

[Table("clinics")]
public class Clinic
{
    [Key]
    public System.Guid ClinicId { get; set; }

    public List<ClinicUser> ClinicUsers { get; set; }
}

ClinicUser.cs

[Table("clinic_users")]
public class ClinicUser
{
    [Key, Column(Order = 0)]
    public string UserId { get; set; }

    [Key, Column(Order = 1)]
    public System.Guid ClinicId { get; set; }

    [ForeignKey("UserId")]
    public virtual ApplicationUser ApplicationUser { get; set; }

    [ForeignKey("ClinicId")]
    public Clinic Clinic { get; set; }
}

另外,我更新了我的 ApplicationUser class 的以下摘录:

[ForeignKey("ClinicUsers")]
public override string Id
{
    get
    {
        return base.Id;
    }
    set
    {
        base.Id = value;
    }
}

public virtual ClinicUser ClinicUsers { get; set; }

对此:

public List<ClinicUser> ClinicUsers { get; set; }

最后,在我的 ApplicationUsersController 的 Index() 操作中,我能够使用这个:

   public async Task<ActionResult> Index()
    {
        if (User.IsInRole("Admin")) return View(await UserManager.Users.ToListAsync());

        var userId = User.Identity.GetUserId();

        //Get the Ids of the current user's clinics
        var userClinics = db.ClinicUsers.Where(cu => cu.UserId == userId).Select(cu => cu.ClinicId).ToList();

        //Get all userIds of the user at the current user's clinics 
        var clinicUserIds = db.ClinicUsers.Where(cu => userClinics.Contains(cu.ClinicId)).ToList().Select(cu => cu.UserId);

        var users = UserManager.Users.Where(u => clinicUserIds.Contains(u.Id));

        return View(await users.ToListAsync());
    }

本质上,如果用户具有 "Admin" 角色,那么他们将获得数据库中所有用户的列表。如果不是,他们将只会获得也属于他们共同诊所的用户列表。

它可能并不完美,但它确实有效。如果有人对如何改进这一点有任何建议,我将很高兴听到。

再次感谢 Archil (https://whosebug.com/users/4089212/archil-labadze) 的有用回复。

首先不要在ApplicationUserclass中使用太多属性,你可以管理用户配置文件table并将其与应用程序用户class连接起来,这样你就可以放很多信息关于个人资料 table 中的用户。 下一个任务是组织 table 诊所、分支机构等...并将应用程序用户与他们联系起来。 接下来你有2种方式: 1. 将应用程序用户与诊所或分支机构相关联。 要么 2. 用角色管理他们。

以下是应用程序用户的示例:

[Table("Clinics")]
public class Clinic
{
    [Key]
    public string Id { get; set; }

    public virtual ICollection<ClinicUser> ClinicUsers { get; set; }
}

[Table("ClinicUsers")]
public class ClinicUser
{
    [Key]
    [Column(Order = 0)]
    public string ClinicId { get; set; }

    [Key]
    [Column(Order = 1)]
    public string UserId { get; set; }
}

接下来您需要其他 ViewModel 来显示它们,希望对您有所帮助。

更新

// GET: ClinicUsers by Clinic
    public async Task<ActionResult> ViewCurrentClinicUsers(string id) // This is clinis ID
    {
        if (id == null)
        {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }
        Clinic clinic = await db.clinic.FindAsync(id); // Get Selectedclinic
        if (clinic == null)
        {
            return HttpNotFound();
        }
        ClinicUsers model = new ClinicUsers() // ClinicUsers model
        {
            clinic = clinic, // View Currentclinic
            ClinicUsers = await db.ClinicUsers.Were(x => x.clinicid == clinic.id)ToListAsync()) // Get Users that asigned to current clinic
        };
        return View(model);
    }

更新 2 最后,如果你想显示诊所,则分配给当前登录用户

// GET: Clinics by currentuser
    public async Task<ActionResult> ViewClinicsWithCurrentUserAccess() 
    {
        var currentuserId = User.Identity.GetUserId(); // This gets currentloged user id
        var currentuser = await db.Users.SingleOrDefaultAsync(x => x.Id == myUserId); // This gets currentloged user virtual
        return View(await db.Clinics.Were(x => x.clinicuserid == currentuserId).ToListAsync());
    }