Django 中自定义构建装饰器的安全问题

时间:2021-01-04 18:31:13

标签: python django

我正在 Django 中使用自定义构建装饰器。

我的decorators.py

from django.contrib.auth import REDIRECT_FIELD_NAME
from django.contrib.auth.decorators import user_passes_test

def industry_required(function=None, redirect_field_name=REDIRECT_FIELD_NAME, login_url='app2:request_login'):
    actual_decorator = user_passes_test(
        lambda u: u.is_active and u.is_Industry,
        login_url=login_url,
        redirect_field_name=redirect_field_name
    )
    if function:
        return actual_decorator(function)
    return actual_decorator

这里的 is_Industry 是一个布尔值,来自models.py。

我的views.py

@method_decorator(industry_required, name='dispatch')
class industryDetails(DetailView):
    model = Industry
    template_name = 'app/industryDetails.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['inserted_text'] = "inserted text from EmployeeDetails of views.py"
        return context

urls.py中:

path('industryDetails/<int:pk>/', views.industryDetails.as_view(), name='industryDetails')

models.py 如果需要,也包括在内:

class myCustomeUser(AbstractUser):
    id = models.AutoField(primary_key=True)
    username = models.CharField(max_length=20, unique="True", blank=False)
    password = models.CharField(max_length=20, blank=False)
    is_Employee = models.BooleanField(default=False)
    is_Inspector = models.BooleanField(default=False)
    is_Industry = models.BooleanField(default=False)
    is_Admin = models.BooleanField(default=False)


class Industry(models.Model):
    user = models.OneToOneField(myCustomeUser, on_delete=models.CASCADE, primary_key=True, related_name='industry_releted_user')
    name = models.CharField(max_length=200, blank=True)
    owner = models.CharField(max_length=200, blank=True)
    license = models.IntegerField(null=True, unique=True)
    industry_extrafield = models.TextField(blank=True)

现在我的问题是,假设拥有 primary_key=3 的用户可以通过使用 primary_key=2(通过更改此地址路径中的主键)轻松访问具有 http://127.0.0.1:8000/industryDetails/2/ 的另一个用户的数据.我需要为我的项目停止这个。我该如何编码,让任何用户都只能访问他自己的详细信息?

1 个答案:

答案 0 :(得分:2)

这与装饰器本身无关,您只需要过滤以防止人们访问另一个 Industry,因此:

@method_decorator(industry_required, name='dispatch')
class industryDetails(LoginRequiredMixin, DetailView):
    model = Industry
    template_name = 'app/industryDetails.html'

    def get_queryset(self):
        return Industry.objects.filter(user=self.request.user)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['inserted_text'] = "inserted text from EmployeeDetails of views.py"
        return context

然而,由于每个用户最多可以拥有 一个 Industry,因此您可能不应该向 URL 添加主键。因此,您可以定义如下路径:

path('industryDetails/', views.industryDetails.as_view(), name='industryDetails')

并在视图中覆盖 get_object 方法:

from django.shortcuts import get_object_or_404

@method_decorator(industry_required, name='dispatch')
class industryDetails(LoginRequiredMixin, DetailView):
    model = Industry
    template_name = 'app/industryDetails.html'

    def get_object(self):
        return get_object_or_404(Industry, user=self.request.user)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['inserted_text'] = "inserted text from EmployeeDetails of views.py"
        return context