安全访问部分属性

时间:2022-12-01 11:23:18

In my application I have two roles (admin and normal). In model I have class (example):

在我的应用程序中,我有两个角色(管理员和普通人)。在模型中我有类(示例):

public class Foo
{
    [Key]
    public int Id { get; set; }

    public string Name { get; set; }

    public string Extra { get; set; }
}

Users can also edit that objects and use filters to search. Application is based on WebAPI ASP.NET Core with EF Core.

用户还可以编辑该对象并使用过滤器进行搜索。应用程序基于带有EF Core的WebAPI ASP.NET Core。

There is a requirement that normal should not see (or do anything with it) Extra property. Should I protect the data everywhere in application ( services, controllers, data access layer) by splitting model class (or something else) or just format output of endpoints by ignoring properties?

有一个要求,正常不应该看到(或做任何事情)额外的财产。我应该通过拆分模型类(或其他东西)来保护应用程序(服务,控制器,数据访问层)中的数据,还是通过忽略属性来格式化端点输出?

One of my ideas is to create an attribute, put it on Extra property and then, using ContractResolver ignoring properties with that attribute when user is not eligible to see that property. Also modify EF change tracker to ignore saving that property (in same cases).

我的一个想法是创建一个属性,将其放在Extra属性上,然后使用ContractResolver在用户没有资格查看该属性时忽略具有该属性的属性。同时修改EF更改跟踪器以忽略保存该属性(在相同情况下)。

Is there any pattern or strategy how to handle with that problem?

有没有任何模式或策略如何处理这个问题?

1 个解决方案

#1


0  

There's no built-in mechanism for this, no, because it's far too granular. Also, trying to enforce this at the EF level would mean leaking your HttpContext into your DAL, which is a bad idea for a number of reasons.

没有内置的机制,不,因为它太细粒度了。此外,尝试在EF级别强制执行此操作意味着将您的HttpContext泄漏到DAL中,出于多种原因这是一个坏主意。

My best recommendation would be to model it with inheritance. In other words, create something like:

我最好的建议是用继承建模。换句话说,创建类似于:

public class Foo
{
    [Key]
    public int Id { get; set; }

    public string Name { get; set; }
}

public class ExtraFoo : Foo
{
    public string Extra { get; set; }
}

By default, Entity Framework will implement this via single-table inheritance, so your backing table will look pretty much exactly the same. However, this then gives you the ability to work with one or the other separately.

默认情况下,Entity Framework将通过单表继承实现此功能,因此您的支持表看起来几乎完全相同。但是,这使您可以单独使用其中一个或另一个。

Then, I would recommend employing completely separate controllers and/or actions for working with each type. This allows you employ different authorization for each, ensuring that "normal" users will only ever be able to work with Foo (rather than ExtraFoo). To negate the obvious duplication this would imply, you can employ a base controller utilizing generics that each type-specific controller could then inherit from:

然后,我建议使用完全独立的控制器和/或操作来处理每种类型。这允许您为每个用户使用不同的授权,确保“普通”用户只能使用Foo(而不是ExtraFoo)。为了消除这意味着明显的重复,你可以使用一个基本控制器,利用泛型,每个类型特定的控制器可以继承:

public class BaseFooController<TFoo> : Controller
    where TFoo : Foo, new()
{
    // all your actions here, utilizing generic type, e.g.:

    [HttpPost]
    public ActionResult Create(TFoo foo)
    {
        ...
    }
}

[Authorize(Roles = "normal")]
public class FooController : BaseFooController<Foo>
{
}

[Authorize(Roles = "admin")]
public class ExtraFooController : BaseFooController<ExtraFoo>
{
}

#1


0  

There's no built-in mechanism for this, no, because it's far too granular. Also, trying to enforce this at the EF level would mean leaking your HttpContext into your DAL, which is a bad idea for a number of reasons.

没有内置的机制,不,因为它太细粒度了。此外,尝试在EF级别强制执行此操作意味着将您的HttpContext泄漏到DAL中,出于多种原因这是一个坏主意。

My best recommendation would be to model it with inheritance. In other words, create something like:

我最好的建议是用继承建模。换句话说,创建类似于:

public class Foo
{
    [Key]
    public int Id { get; set; }

    public string Name { get; set; }
}

public class ExtraFoo : Foo
{
    public string Extra { get; set; }
}

By default, Entity Framework will implement this via single-table inheritance, so your backing table will look pretty much exactly the same. However, this then gives you the ability to work with one or the other separately.

默认情况下,Entity Framework将通过单表继承实现此功能,因此您的支持表看起来几乎完全相同。但是,这使您可以单独使用其中一个或另一个。

Then, I would recommend employing completely separate controllers and/or actions for working with each type. This allows you employ different authorization for each, ensuring that "normal" users will only ever be able to work with Foo (rather than ExtraFoo). To negate the obvious duplication this would imply, you can employ a base controller utilizing generics that each type-specific controller could then inherit from:

然后,我建议使用完全独立的控制器和/或操作来处理每种类型。这允许您为每个用户使用不同的授权,确保“普通”用户只能使用Foo(而不是ExtraFoo)。为了消除这意味着明显的重复,你可以使用一个基本控制器,利用泛型,每个类型特定的控制器可以继承:

public class BaseFooController<TFoo> : Controller
    where TFoo : Foo, new()
{
    // all your actions here, utilizing generic type, e.g.:

    [HttpPost]
    public ActionResult Create(TFoo foo)
    {
        ...
    }
}

[Authorize(Roles = "normal")]
public class FooController : BaseFooController<Foo>
{
}

[Authorize(Roles = "admin")]
public class ExtraFooController : BaseFooController<ExtraFoo>
{
}