amazon s3およびdjango-匿名ユーザーではなく、私のWebサイトのユーザーのみを許可します

Source django amazon-web-services amazon-s3 boto

アップロードされたユーザー画像を保存するためにAmazons3を使用しています。私の問題は次のとおりです。
  • 許可または被付与者の場合、コンテンツをアップロードまたはダウンロードすることはできません。
  • すべてのユーザーに許可または許可を与えると、すべてのユーザーと(特に)匿名ユーザーが、私が望まないコンテンツを見ることができるようになります。

  • だから、私の質問は、私のウェブサイトのユーザーだけがコンテンツをアップロード、ダウンロード、削除できるようにするにはどうすればよいですか?

    その中で私は次のような条件を持っています:
  • ユーザーをフォローしているユーザー(user1、user2、user3、...)のみ
    (user0)コンテンツをダウンロード/表示できますか?
  • ビューをアップロードしたユーザーのみがコンテンツを削除できます。

  • 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'
    

    更新

    ユーザー間の関係のモデル
    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
                })
    
    推奨答え
    ファイルを直接ロードする場合は、Amazon's Query String Authenticationを使用して、URLに署名を含め、ファイルの取得が許可されていることを確認する必要があります。
    アプリはbotoの Key.generate_url methodを使用してそのようなURLを作成できます。また、リンクが無効になるまでの有効期限を追加する必要があります。

    編集:botoを使用してこれを設定する方法についてのより詳細なdescription 、、、
    その他答え #1
    したがって、Georgeが言ったように、これを機能させるには2つの手順を実行する必要がありますが、ec2インスタンスへのアクセスを許可する代わりに(そのメソッドを使用したことはありません)、特定のキーに権限を付与することをお勧めします(このメソッドを広範囲に使用しました)
  • 必要なユーザーにバケットリソースのフルコントロールを許可します。

  • これがパーミッションの仕組みに関するアマゾンです。これらは簡単ではないため、プリンシパルアカウントが誰であるか、およびそのキーを使用しているか、IAMユーザーのキーを使用しているかを理解する必要があります。とにかく、あなたの鍵はリソースへの完全なアクセス権を持っている必要があります(それがあなたのバケツであり、他の誰かのものではないことを願っています、それならもう少し複雑です)
    http://docs.aws.amazon.com/AmazonS3/latest/dev/s3-access-control.html
  • ビジネスロジックを次のように実装します。
  • を使用すると、アプリユーザーはS3ファイルを作成できます
  • を使用すると、ユーザーXをフォローしているユーザーは、ユーザーXによって作成されたファイルを表示/ダウンロードできます。
  • は、ユーザーXのみが自分で作成したファイルを削除できるようにします

  • リソースを作成する場合:
    -提供したバックエンドが機能し、S3権限を適切に設定している場合は、何もする必要はありません。ただし、キーが問題ではないことを確認するには、次のようにします。
    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
    

    すべてが正常に機能する場合は、S3ブラウザーでファイルを表示できるはずです。そうでない場合は、S3アクセス権に関するドキュメントに戻る必要があります。

    ユーザーXをフォローしているユーザーのみに、ユーザーがアップロードしたファイルへのアクセスを許可するには、次のようにします。models.pyファイルには、followロジックをどのように実装したかが記載されていません。誰が誰をフォローしているのかわかりません。独自のカスタムUserモデルはありますか? Djangoを使用していますが、拡張子が付いていますか?ユーザーをリンクする独自のモデルはありますか?あるユーザーが別のユーザーを「フォロー」する方法についての詳細を共有すると、コードフラグメントを共有することもできます。

    ユーザーXが自分のファイルを削除できるようにするには:
    Status.userフィールドには、画像を作成したユーザーへの参照がすでに含まれていると思います。もしそうなら:これをあなたの見解に入れてください:
    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
    
    その他答え #2
    boto3が出ているので、次を使用できます。
    https://github.com/boto/boto3/blob/develop/docs/source/guide/s3-presigned-urls.rst

    import boto3
    s3_client = boto3.client('s3')
    try:
        response = s3_client.generate_presigned_url(ClientMethod=client_method_name,
                                                    Params=method_parameters,
                                                    ExpiresIn=expiration,
                                                    HttpMethod=http_method)
    except ClientError as e:
        logging.error(e)
        return None
    # The response contains the presigned URL
    return response
    

    同じ参照リンクにオブジェクトをアップロードするために同様の方法を使用することもできます。
    その他答え #3
    これは、ビューとテンプレートによって処理されるロジックです。
    たとえば、テンプレートでは、uploadformを使用してこの{% if user.is_authenticated %}のようなブロックを作成できます。ビューでは、ユーザーが認証されているかどうかを確認してから、s3にコンテンツをロードすることもできます。
    その他答え #4
    そのため、aws.s3の部分と話すことはできませんが、djangoの場合、ビューにアクセスできるユーザーを制限する最善の方法は、djangoのlogin_requiredデコレーターを介してログインすることを要求することです。
    from django.contrib.auth.decorators import login_required
    
    @login_required
    def my_view(request):
        ...
    

    または、ページの一部(リンクなど)ではなくすべてのビューを公開したい場合は、@ t_ioが言ったように、その情報をテンプレートに入れることができますが、djangoドキュメントでは、処理ロジックを多すぎないようにすることを強くお勧めしますテンプレートでは、サイトの速度が低下するためです。その情報をビューに配置することをお勧めします。
    @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)
    

    テンプレートでは、リストを歩くことができます
    {% for img in mine %}
        <li><a href=...></a></li>
    {% endfor %}
    
    {% for img in following %}
        <li><a href=...></a></li>
    {% endfor %}
    

    ...あなたはアイデアを得る

    人々がメディアのURLに直接移動するのを防ぐために、sendfile(pythonライブラリ)または同等のapache / nginxを使用できます。したがって、別のビューが必要になります。
    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))
    

    次に、追加のURL(urls.py)が必要になります。
    urlpatterns = patterns('',
        url(r'/media/(?P<path>[a-zA-Z0-9_- /]+)$', views.handle_media),
    )
    

    sendfileでの使用についてはdjango-sendfileを参照してください

    関連記事

    HRESULTからの例外:System.Runtime.InteropServices.COMExceptionの0x8002000B(DISP_E_BADINDEX)
    Javascriptブラウザのスペルチェッカーへのアクセス
    Djangoモジュールのインポート時のVSCodeエラー
    Django os.environを使用するときにDEBUG値を無視するのはなぜですか?
    無効なブロックタグ: 'endblock'。このタグを登録またはロードするのを忘れましたか?