2009-09-23 42 views
8

Tôi đang cố triển khai kiểm tra bảo mật dựa trên hàng cho các mô hình Django. Ý tưởng là khi tôi truy cập trình quản lý mô hình, tôi chỉ định một số thông tin bổ sung được sử dụng trong truy vấn cơ sở dữ liệu để chỉ các cá thể được phép mới được tìm nạp từ cơ sở dữ liệu.Mô hình Django - chuyển thông tin bổ sung cho người quản lý

Ví dụ: chúng tôi có thể có hai kiểu: Người dùng và, nói, Mục. Mỗi mục thuộc về một số người dùng và người dùng có thể được kết nối với nhiều mục. Và để có một số hạn chế, theo đó người dùng có thể thấy hoặc không thể thấy các mục của một người dùng khác. Tôi muốn tách riêng những hạn chế này từ các yếu tố truy vấn khác và viết một cái gì đó như:

items = Item.scoped.forceRule('user1').all() # all items visible for 'user1' 

hoặc

# show all items of 'user2' visible by 'user1' 
items = Item.scoped.forceRule('user1').filter(author__username__exact = 'user2') 

Để đạt được điều này tôi đã thực hiện như sau:

class SecurityManager(models.Manager): 

    def forceRule(self, onBehalf) : 
     modelSecurityScope = getattr(self.model, 'securityScope', None) 
     if modelSecurityScope : 
      return super(SecurityManager, self).get_query_set().filter(self.model.securityScope(onBehalf)) 
     else : 
      return super(SecurityManager, self).get_query_set() 

    def get_query_set(self) : 
     # 
     # I need to know that 'onBehalf' parameter here 
     # 
     return super(SecurityManager, self).get_query_set() 

class User(models.Model) : 
    username = models.CharField(max_length=32, unique=True) 

class Item(models.Model) : 
    author = models.ForeignKey(User) 
    private = models.BooleanField() 
    name = models.CharField(max_length=32) 

    scoped = SecurityManager() 

    @staticmethod 
    def securityScope(onBehalf) : 
     return Q(author__username__exact = onBehalf) | Q(bookmark__private__exact = False) 

Đối với ví dụ cho thấy nó hoạt động tốt , nhưng chết theo sau:

items = Item.scoped.forceRule('user1').filter(author__username__exact = 'user2') # (*) 
items2 = items[0].author.item_set.all() # (**) 

Chắc chắn, items2 được điền bởi tất cả các mục của 'user2', không chỉ những mục phù hợp với quy tắc. Đó là bởi vì khi tất cả() được thực hiện SecurityManager.get_query_set() không có thông tin về bộ hạn chế. Mặc dù nó có thể. Ví dụ, trong forceRule() tôi có thể thêm một trường cho mỗi cá thể và sau đó, nếu tôi có thể truy cập trường đó từ người quản lý, hãy áp dụng quy tắc cần thiết.

Vì vậy, câu hỏi là - có cách nào để chuyển đối số được cung cấp cho forceRule() trong tuyên bố (*) cho người quản lý, được gọi trong tuyên bố (**).

Hoặc một câu hỏi khác - tôi có đang làm những điều kỳ lạ mà tôi không nên làm gì cả?

Cảm ơn bạn.

+0

Tôi cũng đang đối mặt với trường hợp sử dụng tương tự, tôi tự hỏi cách bạn xoay xở để giải quyết vấn đề này? cảm ơn! – ultrajohn

Trả lời

4

Từ đọc sách của tôi trong những tài liệu tôi nghĩ rằng có hai vấn đề:

  1. Các SecurityManager sẽ không được sử dụng cho các đối tượng có liên quan (và thể hiện của django.db.models.Manager sẽ được sử dụng thay)
  2. Bạn có thể sửa lỗi ở trên, nhưng tài liệu đi tới tuyệt vời lengths để chỉ định rằng get_query_set() không nên lọc ra bất kỳ hàng nào cho các truy vấn có liên quan.

Tôi khuyên bạn nên tạo một hàm lấy QuerySet và áp dụng bộ lọc bạn cần cho nó. Điều này sau đó có thể được sử dụng bất cứ khi nào bạn nhận được một QS of Items và muốn xử lý chúng hơn nữa.

+0

Cảm ơn bạn đã trả lời. 1. Tôi đọc tài liệu và rất ngạc nhiên khi trong 'các mục [0] .author.item_set.all()' Django được gọi là SecurityManager.get_query_set(). Tôi đã không yêu cầu họ với use_for_related_fields. Nhưng đó là người quản lý duy nhất cho mô hình, có thể nó quan trọng. 2. Có, tôi đã đọc nó nhưng vẫn nghĩ rằng đó không phải là trường hợp của tôi, bởi vì tôi thực sự muốn Django thấy không phải tất cả cơ sở dữ liệu mà là một phần của nó. Có lẽ, tôi sẽ làm như bạn đề xuất, nhưng câu hỏi của tôi không phải là cách lọc ra dữ liệu không liên quan, nhưng để làm cho việc lọc này dễ dàng và tự động nhất có thể. –

Các vấn đề liên quan