简体   繁体   中英

How to apply read/write permissions to user-uploaded files in Django

I have a "document" model, an upload system using dropzone.js and the register/login. Im now lost on how to apply permissions to each individual uploaded File so only the specified users can access them.

Basically: File1->accessible_by = user1,user2

File2->accesible_by=user3,user5...

And so on.

Thanks to anyone for advice/help on my problem.

Edit with relevant code:

Create Document View:

class DocumentCreate(CreateView):
    model = Document
    fields = ['file', 'is_public']

    def form_valid(self, form):
        self.object = form.save()
        data = {'status': 'success'}
        response = JSONResponse(data, mimetype =
        response_mimetype(self.request))
        return response

I did the above to the view to handle dropzone.js file uploading.

This is my "document" model

class Document(models.Model):

    file = models.FileField(upload_to = 'files/')
                                #validators=[validate_file_type])
    uploaded_at = models.DateTimeField(auto_now_add = True)
    extension = models.CharField(max_length = 30, blank = True)
    thumbnail = models.ImageField(blank = True, null = True)
    is_public = models.BooleanField(default = False)

    uploaded_by = models.ForeignKey(User,
                                related_name='uploadedByAsUser', null=True)

    allowed_users = models.ManyToManyField(User,
                                related_name='allowedUsersAsUser')

    def clean(self):
        self.file.seek(0)
        self.extension = self.file.name.split('/')[-1].split('.')[-1]
        if self.extension == 'xlsx' or self.extension == 'xls':
            self.thumbnail = 'xlsx.png'
        elif self.extension == 'pptx' or self.extension == 'ppt':
            self.thumbnail = 'pptx.png'
        elif self.extension == 'docx' or self.extension == 'doc':
            self.thumbnail = 'docx.png'


    def delete(self, *args, **kwargs):
        #delete file from /media/files
        self.file.delete(save = False)
        #call parent delete method.
        super().delete(*args, **kwargs)

    #Redirect to file list page.
    def get_absolute_url(self):
        return reverse('dashby-files:files')

    def __str__(self):
        return self.file.name.split('/')[-1]

    class Meta():
        ordering = ['-uploaded_at']

You can add an allowed_user field into the document model, so that only those users specified can access the files. for example:

class Document(models.Model):
    file = FileField()
    uploaded_by = models.ForeignKey(User, related_name='uploadedByAsUser')
    allowed_users = models.ManyToManyField(User, related_name='allowedUsersAsUser')

This way, if you want a user to be added to the "allowed" list, you can just add them using something like this:

class DocumentCreate(CreateView):
    model = Document
    fields = ['file', 'is_public']

    def form_valid(self, form):
        self.object = form.save(commit=False)
        self.object.allowed_users.add(request.user)
        self.object.save()
        data = {'status': 'success'}
        response = JSONResponse(data, mimetype =
        response_mimetype(self.request))
        return response

Then to make the Admin look nice (admin.py):

class DocumentAdmin(admin.ModelAdmin):
    list_display = ('uploaded_by', 'file')

    fields = ('id', 'file', 'uploaded_at', 'extension', 'thumbnail', 'is_public', 'uploaded_by', 'allowed_users')
    filter_horizontal = ('allowed_users',)

    readonly_fields = ('id',)

admin.site.register(Document, DocumentAdmin)

Then if you want to check if they're allowed, you can do:

if allowed_user in doc.allowed_users:
    print('We have liftoff')

You can set content_type on a HttpResponse. So you can do permission handling in your view and serve the file directly from Django:

return HttpResponse("Text only, please.", content_type="text/plain")

Note: Django isn't a web server. It is recommended to use a web server for serving static files!

The above method might be a good approach if you handle small amounts of data and only incidentally serve data. If you need a robust solution, you need to check permissions in Django and leave the serving of data to the web server.

  • Lighthttpd X-Sendfile
  • Apache mod_wsgi Internal redirects
  • NGNIX X-Accel-Redirect

Have a look at Django file streaming packages: https://djangopackages.org/grids/g/file-streaming/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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