简体   繁体   English

如何使用asp.net Identity 2.0授权用户仅查看自己的记录

[英]How to authorize a user to only see his own records with asp.net Identity 2.0

There must be an easy solution for such a generic question, so I apologize upfront for my ignorance: 对于这样一个普遍的问题,必须有一个简单的解决方案,因此我为自己的无知向您道歉:

I have a multi-user Web-app (Asp.net MVC5 with EF6) that ao allows users to view and/or modify their relevant data stored in several related tables (Company, Csearch, Candidate). 我有一个多用户Web应用程序(带有EF6的Asp.net MVC5),它允许用户查看和/或修改存储在几个相关表(公司,搜索,候选人)中的相关数据。 (for more details see below). (有关更多详细信息,请参见下文)。 They should NOT see any other data (eg by tampering with the URL). 他们不应看到任何其他数据(例如,通过篡改URL)。

I use Asp.net Identity 2.0 for authentication and would like to use it for the mentioned authorization as well. 我使用Asp.net Identity 2.0进行身份验证,也希望将其用于上述授权。 Userdata is stored in the standard AspNetUser Table. 用户数据存储在标准的AspNetUser表中。 I use only one context for both Identity and my Business Tables. 我仅对身份和业务表使用一种上下文。

I guess I have to either use Roles or maybe Claims to solve this, but I cannot find any guidance on how to do that. 我想我必须使用“角色”或“声明”来解决此问题,但是我找不到有关如何执行此操作的指导。 Can anyone point me in the right direction? 谁能指出我正确的方向?

I have currently solved it (for the Company Model) by adding a LINQ condition to the CompanyController, but this does not appear to be a very secure and proper way of solving the problem. 我目前已通过在CompanyController中添加LINQ条件来解决(针对公司模型),但这似乎不是解决问题的非常安全且正确的方法。

public ActionResult Index(int? id, int? csearchid)
        {
            var companies = db.Companies
              .OrderBy(i => i.CompanyName)
              .Where(t => t.UserName == User.Identity.Name);
        return View(companies);

My DataModel is straightforward and I had it scaffolded using Visual Studio 2017 Through EF6 Code first I have constructed a Relational Datamodel which is roughly as follows: 我的DataModel非常简单,我首先使用Visual Studio 2017通过EF6代码将其搭建起来,然后构建了一个关系数据模型,大致如下:

a COMPANY can have multiple SEARCHES (one to many). 一个公司可以有多个搜索(一对多)。 Each Search can have multiple CANDIDATES (one to many). 每个搜索可以有多个候选人(一对多)。 A COMPANY can have multiple USERS logging in. Users are save in the AspNetUsers table genberated by ASP.Net Identity. 一个COMPANY可以有多个USERS登录。用户保存在ASP.Net Identity生成的AspNetUsers表中。

My Company model looks as follows: 我的公司模型如下所示:

public class Company
{
    public int CompanyID { get; set; }

    // Link naar de Userid in Identity: AspNetUsers.Id
    [Display(Name = "Username")]
    public string UserName { get; set; }        
    public string CompanyName { get; set;}
    public string CompanyContactName { get; set; }
    [DataType(DataType.EmailAddress)]        
    public string CompanyEmail { get; set; }
    public string CompanyPhone { get; set; }        

    [Timestamp]
    public byte[] RowVersion { get; set; }

    //One to Many Navigatie links
    public virtual ICollection<Csearch> Csearches { get; set; }

Once the user is identified, you can make sure the user can only access its own data. 识别用户后,您可以确保该用户只能访问自己的数据。 You cannot use roles for that, since that will only define the level of access. 您不能为此使用角色,因为这只会定义访问级别。 But you can use claims. 但是您可以使用声明。

Out-of-the-box there is a seperation of concerns . 开箱即用的关注点分开的 Maintain this seperation. 保持此分隔。 You are not meant to query the Identity tables directly. 您无意直接查询身份表。 Use the userManager for that. 为此使用userManager。 Also never use an Identity object as ViewModel. 也不要将Identity对象用作ViewModel。 You may expose more than you mean to. 您可能会暴露出意想不到的东西。 If you keep this seperation, you'll see that it is in fact much easier. 如果保持这种分隔,您会发现它实际上要容易得多。

The identity context contains all data to identify the user, the business context contains all business information, including user information. 身份上下文包含标识用户的所有数据,业务上下文包含所有业务信息,包括用户信息。 You may think that this is redundant, but the login user has really nothing in common with the business user. 您可能会认为这是多余的,但是登录用户与业务用户之间确实没有任何共同之处。 The login emailaddress may differ from the business.user.emailaddress (what is the meaning of the emailaddress in both cases?). 登录电子邮件地址可能与business.user.emailaddress不同(两种情况下电子邮件地址的含义是什么?)。 Also consider the possibility to have users that cannot login (anymore). 还请考虑使用户无法登录(不再)的可能性。

As a rule of thumb always consider if the information is part of the identity or part of the business. 根据经验,应始终考虑信息是身份的一部分还是业务的一部分。

When do you need the ApplicationUser? 什么时候需要ApplicationUser? Only for the current user or when managing users. 仅适用于当前用户或管理用户时。 When you query users, always use the business.user. 查询用户时,请始终使用business.user。 Because all the information you need should be available there. 因为您需要的所有信息都应该在那里。

For the current user, add claims with the information you need. 对于当前用户,请添加具有所需信息的声明。 The advantage of claims is that you won't have to query the database on each call to retrieve this information, like the corresponding UserId and the (display)UserName. Claims的优点是,您不必在每次调用时都查询数据库来检索此信息,例如相应的UserId和(display)UserName。

How to add claims 如何添加索赔

You can, without having to extend the ApplicationUser class, add a claim to the user by adding a row to the AspNetUserClaims table. 您可以不必扩展ApplicationUser类,而可以通过向AspNetUserClaims表中添加一行来向用户添加声明。 Something like: 就像是:

userManager.AddClaim(id, new Claim("UserId", UserId));

On login the claim will be automatically added to the ClaimsIdentity. 登录后,索赔将自动添加到ClaimsIdentity。

You can also add claims for properties that extend the ApplicationUser: 您还可以为扩展ApplicationUser的属性添加声明:

public class ApplicationUser : IdentityUser
{
    public int UserId { get; set; }

    public string DisplayUserName { 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.AddClaim(new Claim("UserId", UserId));
        userIdentity.AddClaim(new Claim("DisplayUserName", DisplayUserName));

        return userIdentity;
    }
}

How to read claims 如何阅读索赔

In the controller you can read the claim with code like this: 在控制器中,您可以使用以下代码读取声明:

var user = (System.Security.Claims.ClaimsIdentity)User.Identity;
var userId = user.FindFirstValue("UserId");

You can use userId in your queries to filter the data for the current user or even use business.users as the only entry to retrieve data. 您可以在查询中使用userId来过滤当前用户的数据,甚至可以使用business.users作为检索数据的唯一条目。 Like db.Users(u => u.Id == userId).Companies.ToList(); 就像db.Users(u => u.Id == userId).Companies.ToList();

Please note, the code is just an example. 请注意,代码仅是示例。 I didn't test all of it. 我没有测试所有。 It is just to give you an idea. 这只是给您一个想法。 In case something isn't clear, please let me know. 如果有不清楚的地方,请告诉我。

It's pretty simple really. 真的很简单。 To illustrate with the example Company you provided. 为了说明您提供的示例公司。 Note that you should use UserId to join rather than UserName since UserName can change, but UserId will always be unique.) 请注意,您应该使用UserId而不是UserName进行加入,因为UserName可以更改,但UserId始终是唯一的。)

Instead of having UserName in your Company table, you need to change that to UserId. 您需要将其更改为UserId,而不是在Company表中包含UserName。 Then you join the AspNetUsers table with your Company table on UserId. 然后,将AspNetUsers表与UserId上的Company表联接在一起。

For example (I prefer to use the query syntax rather than the fluent syntax): 例如(我更喜欢使用查询语法而不是流利的语法):

var companies = from c in db.Companies join u in db.AspNetUsers
                on c.UserId equals u.UserId
                orderby c.CompanyName
                where u.UserName = User.Identity.Name 
                select c;

If you need the username as well, then include that in your select 如果还需要用户名,则将其包括在您的选择中

select new { Company = c, User = u.UserName };

However, this model does not work if you want to have multiple users per company. 但是,如果您希望每个公司有多个用户,则此模型不起作用。 You either need to add CompanyId to the users table (assuming a user can't be a member of more than one company) or create a many-to-many join if a user can be a member of multiple companies. 您或者需要将CompanyId添加到用户表(假设一个用户不能是一个以上公司的成员),或者如果一个用户可以是多个公司的成员,则需要创建多对多联接。

So rather than linking the user to the company, you link the company to the user. 因此,不是将用户链接到公司,而是将公司链接到用户。 Your current model only allows one user per company. 您当前的模型每个公司只允许一个用户。

Another thing I see wrong here is the use of DisplayName in your entity object. 我在这里看到的另一件事是在您的实体对象中使用DisplayName。 That seems to indicate you are using the entity in your MVC view, which you shouldn't do. 这似乎表明您正在MVC视图中使用实体,您不应该这样做。 You should create a separate ViewModel. 您应该创建一个单独的ViewModel。

Here is how it should look like for multiple users per company: 每个公司的多个用户的外观如下:

public class Company
{
    public int CompanyID { get; set; }

    // Link naar de Userid in Identity: AspNetUsers.Id
    // [Display(Name = "Username")] <-- Get rid of these
    // public string UserName { get; set; } <-- get rid of these
...
}

public class ApplicationUser : IdentityUser
{
    public int CompanyId { get; set; }
}

Then change your query to: 然后将查询更改为:

var companies = from c in db.Companies join u in db.AspNetUsers
            on c.CompanyId equals u.CompanyId // <-- Change to this
            orderby c.CompanyName
            where u.UserName = User.Identity.Name 
            select c;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使用新的ASP.NET Identity 2.0角色和授权属性? - How to use new ASP.NET Identity 2.0 Roles and Authorize Attribute? ASP.NET MVC属性只允许用户编辑自己的内容 - ASP.NET MVC Attribute to only let user edit his/her own content asp.net Identity 2.0可以在自己的项目中运行吗? - Can asp.net identity 2.0 run in it's own project? 如何让用户创建自己的数据库asp.net网站 - how to let user create his own database asp.net website ASP.NET MVC上的Windows Identity Framework-如何基于操作授权用户? - Windows Identity Framework on ASP.NET MVC - how to authorize user per action basis? ASP.NET身份-如何仅允许访问已登录的用户? - ASP.NET Identity - How to allow access to ONLY the logged in User? ASP.NET Core 2.0 Identity仅在重新授权后才更新用户角色 - ASP.NET Core 2.0 Identity update user roles only after re-authorization 将asp.net标识与地理授权一起使用 - Use asp.net identity with geography authorize 如何使用ASP.NET Identity 2.0允许用户模拟其他用户? - How do I use ASP.NET Identity 2.0 to allow a user to impersonate another user? 为什么ASP.NET Core Identity 2.0授权过滤器导致我获得404? - Why is ASP.NET Core Identity 2.0 Authorize filter causing me to get a 404?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM