简体   繁体   English

MVC存储库模式,如何进行安全修整?

[英]MVC repository pattern, how to security trim?

Currently I am writing a web application in MVC 4. I am using a generic repository pattern. 当前,我正在用MVC 4编写Web应用程序。我正在使用通用存储库模式。 It works well. 它运作良好。 So I have something like the followings, 所以我有以下内容

public class AddressRepository : IAddressRepository
    {
        private AISDbContext context = new AISDbContext();

        public IQueryable<Address> GetAddresses()
        {
            return context.Address;
        }

    }

But now I need to add something that filters the data more. 但是现在我需要添加一些可以进一步过滤数据的东西。 Based on the logged in user's role, this data should be more filtered. 根据登录用户的角色,应该对这些数据进行更多过滤。

something like this.. 像这样

public IQueryable<Address> GetAddresses()
{
   return context.Address.where(x=>x.haspermissions = CURENTUSER.Role);
 }

Now I could always add another function like this, but I want to try an be general. 现在,我总是可以添加另一个这样的函数,但是我想尝试一个通用的函数。 I want to know if I can just use the first bit of code and inherit from another class, that just applies the security trimming. 我想知道我是否可以仅使用第一部分代码并从另一个类继承而已,该类仅适用于安全性调整。 This way I do not have to rewrite all my queries, I simply tell each class to inherit from the security trimmer. 这样,我不必重写所有查询,只需告诉每个类从安全调整器继承即可。 hope that makes sense.. 希望有道理..

Thanks 谢谢

updated code 更新的代码

public class AddressRepository : SecureRepositoryBase<Address>, IAddressRepository
    {
        private AISDbContext context = new AISDbContext();

        public IQueryable<Address> GetAll()
        {
            return base.RetrieveSecure(context.Address, 1);           
        }
}

 public abstract class SecureRepositoryBase<T> where T : ISecuredEntity
    {
        public IQueryable<T> RetrieveSecure(IQueryable<T> entities, int currentUser)
        {
            return entities.Where(e => e.InspectorId == currentUser);         
        }
    }

 public interface ISecuredEntity
    {
        int? InspectorId { get; set; }
    }

 public class Address: ISecuredEntity
    {
        public int COESNo { get; set; }
        public int Postcode { get; set; }
        public int AuditAuthNo { get; set; }
        public bool? SelectedForAudit { get; set; }
        public int? RECId { get; set; }
        public string CustomerName { get; set; }
        public string CustomerAddress { get; set; }
        public int? CustomerSuburbId { get; set; }
        public int? InspectorId { get; set; }
        public DateTime? AuditDate { get; set; }
        public int? AuditType { get; set; }
        public int? UploadType { get; set; }
        public string COESImage { get; set; }
        public DateTime CreatedDate { get; set; }
        public int? CreatedBy { get; set; }
        public DateTime? ModifiedDate { get; set; }
        public int? ModifiedBy { get; set; }

        public virtual UserDetails Inspector { get; set; }
        public virtual Postcodes CustomerSuburb { get; set; }
        public virtual ResponsiblePerson RPerson { get; set; }
        public virtual UserProfile CreatedByUser { get; set; }
        public virtual UserProfile ModifiedByUser { get; set; }
    }

Create a base class that converts each query to one where the permissions are checked and let your repository classes inherit from that. 创建一个基类,将每个查询转换为检查权限的查询,并让您的存储库类从中继承。

Something like this: 像这样:

public interface ISecuredEntity
{
    IEnumerable<string> Permissions { get; }
}

public class Address : ISecuredEntity
{
    public IEnumerable<string> Permissions { get; set; }
}

public class AddressRepository : SecureRepositoryBase<Address>, IAddressRepository
{
    private AISDbContext context = new AISDbContext();

    public IQueryable<Address> GetAddresses()
    {
        return base.RetrieveSecure(context.Address, CURENTUSER);
    }
}

public abstract class SecureRepositoryBase<T>
    where T : ISecuredEntity
{
    public IQueryable<T> RetrieveSecure(IQueryable<T> entities, IUser currentUser)
    {
        return entities.Where(e => e.Permissions.Contains(currentUser.Role));
    }
}

You might want to look into global filters. 您可能需要研究全局过滤器。 I'm including a brief example of how it would work: 我将提供一个有关其工作原理的简短示例:

public class AISDbContext : DbContext
{
    public void ApplyFilters(IList<IFilter<AISDbContext>> filters)
    {
        foreach(var filter in filters)
        {
            filter.DbContext = this;
            filter.Apply();
        }
    }
}

public interface IFilter<T> where T : DbContext
{
    T DbContext {get; set;}
    void Apply();
}

public class AdminRoleFilter : IFilter<AISDbContext>
{
    public AISDbContext _dbContext {get; set;}
    public void Apply()
    {
        _dbContext.Address = new FilteredDbSet(_dbContext, d => d.haspermissions = "Admin");
    }
}

The details of the FilteredDbSet are really extensive and can be found here . FilteredDbSet的详细信息确实很广泛,可以在这里找到。

Then the implementation of your DbContext in your AddressRepository would look like this: 那么你的执行DbContextAddressRepository是这样的:

var context = new AISDbContext();
context.ApplyFilters(new List<IFilter<AISDbContext>>()
    {
        new AdminRoleFilter()
    });

public List<Address> GetAddresses()
{
    return context.Address.ToList();
}

MVC repository pattern, how to security trim? MVC存储库模式,如何进行安全修整?

Repository should not take care of access control / security trimming. 存储库不应该进行访问控制/安全调整。 It merely provides methods to query for domain objects . 仅提供查询域对象的方法

In the following code 在下面的代码中

function GetAddresses() as IQueryable(of Address)
function GetAddressesInspectedBy(Inspector as Inspector) as IQueryable(of Address)

The method GetAddresses will return all addresses available. 方法GetAddresses将返回所有可用地址。

The method GetAddressesInspectedBy will return all addresses inspected by the concrete inspector. 方法GetAddressesInspectedBy将返回具体检查员检查的所有地址。

These two methods are clearly distinct and coexist with each other in repository. 这两种方法显然是不同的,并且在存储库中彼此共存。 Both methods should be available, but what method is to be called depends on business logic / access control outside repository. 两种方法都应该可用,但是调用哪种方法取决于存储库外部的业务逻辑/访问控制。

But now I need to add something that filters the data more. 但是现在我需要添加一些可以进一步过滤数据的东西。 Based on the logged in user's role, this data should be more filtered. 根据登录用户的角色,应该对这些数据进行更多过滤。

Data returned to the user should not be based on user's role! 返回给用户的数据不应基于用户的角色! Instead it should be based on user's request! 相反,它应该基于用户的请求! And whether the request may be executed or not depends on user's role. 以及该请求是否可以执行取决于用户的角色。

For example, administrator role user may be allowed to request each of the following 例如,可以允许管理员角色用户请求以下每个请求

  1. all addresses, 所有地址,
  2. addresses by concrete inspector, 具体检查员的地址,
  3. addresses inspected by himself. 由他自己检查的地址。

Each of the three request types returns different results, independent on administrator role! 三种请求类型中的每一种都将返回不同的结果,而与管理员角色无关!

While inspector role user may be allowed to request only 虽然检查员角色用户只能被允许请求

  1. addresses inspected only by himself. 仅由本人检查的地址。

Application receives request, checks whether user is allowed to do this request and calls repository methods corresponding to the request. 应用程序接收请求,检查是否允许用户执行此请求,并调用与该请求相对应的存储库方法。

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM