2015-02-06 11 views
9

Używam Amazon3 do przechowywania przesłanych zdjęć użytkowników. Moje problemy to:amazon s3 i django - zezwalaj tylko użytkownikom z mojej witryny, a nie anonimowi użytkownicy

  • Jeśli pozwolę lub otrzymam dla mnie grant, nie mogę przesłać ani pobrać zawartości.
  • Jeśli pozwolę lub przyznaję dla wszystkich, wszyscy użytkownicy i (szczególnie) anonimowi użytkownicy będą mogli zobaczyć zawartość, której nie chcę.

Moje pytanie brzmi: co mam zrobić, aby tylko użytkownicy z mojej witryny mogli przesyłać, pobierać i usuwać zawartość?

tym, że mam warunki:

  1. Tylko użytkownicy (user1, user2, użytkownik3, ...), którzy są następujące użytkownika (user0) można pobrać/obejrzeć zawartość?
  2. Tylko użytkownik, który przesłał widok, może usunąć jego zawartość.

models.py:

def get_upload_file_name(instance, filename): 
    return "uploaded_files/%s_%s" %(str(time()).replace('.','_'), filename) 

PRIVACY = (
    ('H','Hide'), 
    ('F','Followers'), 
    ('A','All'), 
) 

class Status(models.Model): 
    body = models.TextField(max_length=200) 
    image = models.ImageField(blank=True, null=True, upload_to=get_upload_file_name) 
    privacy = models.CharField(max_length=1,choices=PRIVACY, default='F') 
    pub_date = models.DateTimeField(auto_now_add=True, auto_now=False) 
    user = models.ForeignKey(User) 

settings.py:

DEFAULT_FILE_STORAGE = 'storages.backends.s3boto.S3BotoStorage' 

AWS_ACCESS_KEY_ID = 'FAKEAMAZONKEY' 

AWS_SECRET_ACCESS_KEY = 'FAKEAMAZONSECRETKEY' 

AWS_STORAGE_BUCKET_NAME = 'fakebucketname' 

Aktualizacja

Wzór relacji między użytkownikami

class Person(models.Model): 
    user = models.OneToOneField(User) 
    relationships = models.ManyToManyField('self', through='Relationship', 
              symmetrical=False, 
              related_name='related_to') 

    def __unicode__(self): 
     return self.user.username 

    def add_relationship(self, person, status): 
     relationship, created = Relationship.objects.get_or_create(
      from_person=self, 
      to_person=person, 
      status=status) 
     return relationship 

    def remove_relationship(self, person, status): 
     Relationship.objects.filter(
      from_person=self, 
      to_person=person, 
      status=status).delete() 
     return 

    def get_relationships(self, status): 
     return self.relationships.filter(
      to_people__status=status, 
      to_people__from_person=self) 

    def get_related_to(self, status): 
     return self.related_to.filter(
      from_people__status=status, 
      from_people__to_person=self) 

    def get_following(self): 
     return self.get_relationships(RELATIONSHIP_FOLLOWING) 

    def get_followers(self): 
     return self.get_related_to(RELATIONSHIP_FOLLOWING) 

    def get_friends(self): 
     return self.relationships.filter(
      to_people__status=RELATIONSHIP_FOLLOWING, 
      to_people__from_person=self, 
      from_people__status=RELATIONSHIP_FOLLOWING, 
      from_people__to_person=self) 


RELATIONSHIP_FOLLOWING = 1 
RELATIONSHIP_BLOCKED = 2 
RELATIONSHIP_STATUSES = (
    (RELATIONSHIP_FOLLOWING, 'Following'), 
    (RELATIONSHIP_BLOCKED, 'Blocked'), 
) 

class Relationship(models.Model): 
    from_person = models.ForeignKey(Person, related_name='from_people') 
    to_person = models.ForeignKey(Person, related_name='to_people') 
    status = models.IntegerField(choices=RELATIONSHIP_STATUSES) 

    def __unicode__(self): 
     return "%s %s %s" % (self.from_person, self.get_status_display(), self.to_person) 


class Activity(models.Model): 
    actor = models.ForeignKey(User) 
    action = models.CharField(max_length=100) 
    content_type = models.ForeignKey(ContentType, related_name="content_type") 
    object_id = models.PositiveIntegerField() 
    content_object = generic.GenericForeignKey('content_type', 'object_id') 
    element_type = models.ForeignKey(ContentType, related_name="element_type", blank=True, null=True) 
    element_id = models.PositiveIntegerField(blank=True, null=True) 
    element_object = generic.GenericForeignKey('element_type', 'element_id') 
    pub_date = models.DateTimeField(auto_now_add=True, auto_now=False) 

    class Meta: 
     verbose_name = 'Activity' 
     verbose_name_plural = 'Activities' 
     ordering = ['-pub_date'] 

    def __unicode__(self): 
     return ("%s %s") % (self.actor.username, self.action) 

    def get_rendered_html(self, user=None): 
     if self.element_type: 
      template_name = '%s_activity.html' %(self.element_type.name) 
     else: 
      template_name = '%s_activity.html' %(self.content_type.name) 

     return render_to_string(template_name, { 
      'object':self.content_object, 
      'actor':self.actor, 
      'action':self.action, 
      'element_object':self.element_object, 
      'user':user, 
      'pub_date':self.pub_date 
      }) 
+3

Musisz zmienić swoje uprawnienia S3 tylko pozwoli pobrania z serwera, a webapp backend musi odfiltrować, którzy mogą złożyć wnioski do pliku s3 . Używam symfony, więc nie mogę pomóc. Jeśli nie dodasz ograniczeń do s3, każda osoba mająca link może pobrać plik z s3 i jest to zamaskowanie danych. [Zobacz zasady dotyczące wiaderek] (http://docs.aws.amazon.com/AmazonS3/latest/dev/example-bucket-policies.html) – George

+0

@George Tak, właśnie tego chcę. Dodałem Twój komentarz jako przydatny. Mam nadzieję, że ktoś mi pomoże. – Kakar

+0

Spójrz na [dokument i wideo z aws] (http://docs.aws.amazon.com/IAM/latest/UserGuide/roles-usingrole-ec2instance.html) – George

Odpowiedz

1

To jest logika, która jest obsługiwana przez widok i szablon. Na przykład w szablonie możesz mieć blok taki jak {% if user.is_authenticated %} z wysyłką, a w widoku możesz sprawdzić również, czy użytkownik uwierzytelniony i dopiero potem załaduje twoje pliki do s3

+0

Tak, ale mam zupełnie inny problem. Załóżmy, że mamy link do Twojego obrazu (który jest bardzo łatwy do zdobycia), on/ona może łatwo oglądać obraz, nawet jeśli nie jest on użytkownikiem. – Kakar

+0

Możesz utworzyć użytkownika w sekcji Amazon IAM, a następnie ustawić "AWS_STORAGE_BUCKET_NAME", "AWS_ACCESS_KEY_ID" i "AWS_SECRET_ACCESS_KEY", aby przesłać je do swojego zasobnika. Myślę, że możesz także ustawić ustawienia Amazon CORS, aby zezwalać tylko na żądania z twojej domeny. –

4

Podczas bezpośredniego ładowania plików możesz użyć Amazon's Query String Authentication gdzie należy podać podpis w adresie URL, aby zweryfikować, czy masz prawo do pobierania plików. Twoja aplikacja może użyć boto-a Key.generate_url method do utworzenia takiego adresu URL. Powinieneś również dodać czas wygaśnięcia, po którym link nie będzie już ważny.

EDIT: Bardziej SZCZEGÓŁOWY description o tym, jak to skonfigurować przy użyciu boto ,,,

2

Tak jak powiedział George, trzeba wziąć 2 kroki, aby uczynić tę pracę, chociaż zamiast udzielania dostępu do instancji EC2 (nigdy nie używałem tej metody) Polecam tylko przyznanie praw do twoich konkretnych kluczy (użyłem tej metody szeroko)

  1. Zapewnij pełną kontrolę zasobów zasobnika użytkownikowi.

Oto amazon, jak działają uprawnienia. Nie są trywialne, więc musisz zrozumieć, kto jest głównym kontem i czy używasz jego kluczy lub kluczy dla użytkownika IAM.Niezależnie od tego, klucze powinny mieć pełny dostęp do zasobów (mam nadzieję, że to twój wiadro, a nie kogoś innego, bo potem wszystko trochę bardziej skomplikowane) http://docs.aws.amazon.com/AmazonS3/latest/dev/s3-access-control.html

  1. Implementacja logiki biznesowej do:
    • umożliwić użytkownikom aplikacji do tworzenia plików S3
    • umożliwić użytkownikom, którzy są następujące użytkownik X aby pobrać pliki utworzone przez użytkownika/X
    • pozwalają tylko użytkownik X, aby usunąć pliki, że stworzył

Aby utworzyć zasoby: - jeśli dostarczony przez ciebie backend działa i dobrze skonfigurowałeś swoje prawa S3, nie powinieneś robić nic. Jednak, aby sprawdzić, czy klucze nie są problemem, to zrobić:

from boto.s3.connection import S3Connection as s3c 
connection = s3c('your-aws-access-key', 'your-aws-secret-key') 
bucket = connection.get_bucket('your-bucket-name') 

new_key = bucket.new_key('your-key-name') #meaning the name of the file 
# https://github.com/boto/boto/blob/develop/boto/s3/bucket.py#L611 

new_key.send_file(file_object) #this will upload the file 
# https://github.com/boto/boto/blob/develop/boto/s3/key.py#L709 

Jeśli wszystko działa dobrze, powinieneś być w stanie zobaczyć plik w przeglądarce S3 - jeśli nie, będziesz musiał wrócić do dokumentacji o prawach dostępu S3.

Aby zezwolić tylko użytkownicy, którzy są następujące firmy X ma dostęp do plików, które użytkownik przesłanych: Plik models.py nie mówi, w jaki sposób zostały wdrożone logikę follow. Nie mogę powiedzieć, kto podąża za kim. Czy masz własny niestandardowy model User? Czy używasz Django, ale z rozszerzeniem? Czy masz swój własny model, który łączy użytkowników? Udostępnij więcej informacji o tym, jak jeden użytkownik "podąża" za innym, a potem mogę nawet udostępniać fragmenty kodu.

Aby umożliwić użytkownikowi X usuwanie własnych plików: Zgaduję, że pole Status.user będzie zawierało już odniesienie do użytkownika, który utworzył obraz. Jeśli tak, to: umieścić to w widoku:

def picture_deletion_view(request, status_identifier ...): 
    try: 
     status = Status.objects.filter(id_or_some_identifier=status_identifier) 
    except Status.DoesNotExist: 
     return SomeHttpResponse() 

    if request.user.id == status.user.id: 
     # you can delete the picture and redirect... to somewhere 
    else: 
     # you can't delete! redirect...or something 
+0

Dodałem logikę relacji. Proszę spojrzeć na to. Dziękuję Ci. – Kakar

1

więc nie mogę mówić do aws.s3 kawałku, ale dla Django, najlepszym sposobem, aby określić, kto ma dostęp do widzenia jest wymaganie logowanie poprzez Django login_required dekorator:

from django.contrib.auth.decorators import login_required 

@login_required 
def my_view(request): 
    ... 

lub, jeśli chcesz, aby odsłonić wszystkie zdania, ale nie części strony (linki itp), można umieścić te informacje do szablonu, jak @t_io powiedział, ale Dokumenty django zdecydowanie zalecają, aby nie umieszczać zbyt dużej ilości logiki przetwarzania w szablonach, ponieważ spowalnia to działanie witryny. lepiej byłoby umieścić te informacje w widoku:

@login_required 
def image_view(request): 
    user = request.user 

    # this list has the user's own images 
    mine = [] 
    for status in user.status_set.all(): 
     mine.append(status.image) 

    # this list has the images the user can see (relationship-based) 
    following = [] 
    friends = [] 

    # you can get the person from the user 
    person = user.person 

    for status in person.get_friends().all(): 
     friends.append(status.image) 

    for status in person.get_following().all(): 
     following.append(status.image) 

    ctx = dict(user=request.user, friends=friends, following=following, mine=mine) 
    return render("template.html", ctx) 

i w szablonie, można chodzić wykazy

{% for img in mine %} 
    <li><a href=...></a></li> 
{% endfor %} 

{% for img in following %} 
    <li><a href=...></a></li> 
{% endfor %} 

... masz pomysł

aby zapobiec od przejścia bezpośrednio do adresu URL mediów, możesz użyć sendfile (biblioteka python) lub odpowiednik apache/nginx. więc potrzebujesz innego widoku:

import sendfile 
from django.conf import settings 
@login_required 
def handle_media(request, path=None): 
    try: 
     requested_file = os.path.join(settings.MEDIA_ROOT, path) 
     return sendfile.sendfile(request, requested_file) 
    except: 
     pass 

    return HttpResponseNotFound('<h1>Page not found {}</h1>'.format(path)) 

, a następnie potrzebujesz dodatkowego adresu URL (adresy URL.py):

urlpatterns = patterns('', 
    url(r'/media/(?P<path>[a-zA-Z0-9_- /]+)$', views.handle_media), 
) 

zobaczyć django-sendfile do użytku na Sendfile

+0

tak, w jeden sposób. Ale chodzi o to, że jeśli uzyskasz link do obrazu, możesz to łatwo uzyskać, przechodząc do tego adresu URL ... – Kakar

Powiązane problemy