{ "info": { "author": "Stefan Wehrmeyer", "author_email": "mail@stefanwehrmeyer.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Framework :: Django", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Topic :: Internet :: WWW/HTTP" ], "description": "# Cross-Domain Media with authentication for Django\n\n**The situation**: You serve media files from a different domain than your main web application domain (good idea). You want to use [nginx's internal redirect (`X-Accel-Redirect`)](https://nginx.org/en/docs/http/ngx_http_core_module.html#internal) to authorize media file delivery.\n\n**The problem**: You don't have access to the user's session on the media domain and can't authenticate or authorize media access.\n\n**The solution**: You handle media URLs with an expiring token attached which temporarily authorizes access and can be refreshed via redirects when needed.\n\n\n## HTTP View\n\nHere's how it works in HTTP:\n\n1. -> GET media.example.org/path/file.pdf\n2. <- 302 www.example.com/path/file.pdf\n3. -> GET www.example.com/path/file.pdf\n - *if not authorized* <- 403\n - *if authorized* <- 302 media.example.org/path/file.pdf?token=XYZ\n4. -> GET media.example.org/path/file.pdf?token=XYZ\n5. <- 200 file.pdf\n6. *after expiry* -> GET media.example.org/path/file.pdf?token=XYZ\n7. See step 2\n\n\n## Use in Django\n\n```python\n\n# Development\nMEDIA_URL = '/media/'\n\n# Production\n\nMEDIA_URL = 'https://media.example.org/media/\nINTERNAL_MEDIA_PREFIX = '/protected/'\n```\n\n\n```python\n\nfrom crossdomainmedia import (\n CrossDomainMediaAuth, CrossDomainMediaMixin\n)\n\n\nclass CustomCrossDomainMediaAuth(CrossDomainMediaAuth):\n '''\n Create your own custom CrossDomainMediaAuth class\n and implement at least these methods\n '''\n SITE_URL = 'https://www.example.com'\n\n def is_media_public(self):\n '''\n Determine if the media described by self.context\n needs authentication/authorization at all\n '''\n return self.context['object'].is_public\n\n def get_auth_url(self):\n '''\n Give URL path to authenticating view\n for the media described in context\n '''\n obj = self.context['object']\n raise reverse('view-name', kwargs={'pk': obj.pk})\n\n def get_media_file_path(self):\n '''\n Return the file path relative to MEDIA_ROOT\n '''\n obj = self.context['object']\n return obj.file.name\n\n\nclass CustomDetailView(CrossDomainMediaMixin, DetailView):\n '''\n Add the CrossDomainMediaMixin\n and set your custom media_auth_class\n '''\n media_auth_class = CustomCrossDomainMediaAuth\n\n```\n\n### Some other useful methods\n\n```python\n\n# Get your media URLs with token outside of view\nmauth = CustomCrossDomainMediaAuth({'object': obj})\nmauth.get_full_media_url(authorized=True)\n\n# Send file via nginx internal redirect response\nmauth.send_internal_file()\n```\n\n## Nginx config\n\nThis is how an Nginx config could look like.\n\n```nginx\nserver {\n # Web server with session on domain\n listen 443 ssl http2;\n server_name www.example.com;\n # ...\n\n location / {\n proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n proxy_set_header X-Forwarded-Proto https;\n proxy_set_header Host $host;\n # etc...\n\n proxy_pass wsgi_server;\n }\n}\n\nserver {\n # Media server with no session on domain\n\n listen 443 ssl http2;\n server_name media.example.org;\n # ...\n\n location /media/ {\n proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n proxy_set_header X-Forwarded-Proto https;\n proxy_set_header Host $host;\n # etc...\n\n proxy_pass wsgi_server;\n }\n\n location /protected {\n internal;\n\n alias /var/www/media-root;\n }\n}\n```", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/stefanw/django-crossdomainmedia", "keywords": "", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "django-crossdomainmedia", "package_url": "https://pypi.org/project/django-crossdomainmedia/", "platform": "", "project_url": "https://pypi.org/project/django-crossdomainmedia/", "project_urls": { "Homepage": "https://github.com/stefanw/django-crossdomainmedia" }, "release_url": "https://pypi.org/project/django-crossdomainmedia/0.0.3/", "requires_dist": null, "requires_python": "", "summary": "Cross-Domain Media with authentication for Django", "version": "0.0.3" }, "last_serial": 5792873, "releases": { "0.0.1": [ { "comment_text": "", "digests": { "md5": "9eb4a8c683e6485823a3f11f3f44cc5a", "sha256": "c2f0a655ebb4c79a143b5862518d0db6db8e6506951cb0f35deab3dadbc8c6bb" }, "downloads": -1, "filename": "django_crossdomainmedia-0.0.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "9eb4a8c683e6485823a3f11f3f44cc5a", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 6854, "upload_time": "2019-05-28T13:46:52", "url": "https://files.pythonhosted.org/packages/e3/e3/26b980ff2ea5c3d424ebc739bc52c5812003535dba4ff80c4eacfcf6d5bf/django_crossdomainmedia-0.0.1-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "dbf1beabc4cd746183dece98e0ef5119", "sha256": "6ac35214ea29945ef657b1d512a9ca4ce0cd80e91ea224bc98370b0ff0d030ea" }, "downloads": -1, "filename": "django-crossdomainmedia-0.0.1.tar.gz", "has_sig": false, "md5_digest": "dbf1beabc4cd746183dece98e0ef5119", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5282, "upload_time": "2019-05-28T13:46:55", "url": "https://files.pythonhosted.org/packages/e5/e2/befad0e63a04f808383c21569513743294e0a907bd09a807db7c28c562c4/django-crossdomainmedia-0.0.1.tar.gz" } ], "0.0.2": [ { "comment_text": "", "digests": { "md5": "a166b4ad94131ce6a3a29808c9e0784e", "sha256": "dcb7e66591dd7665f4240b4b72e93f7d8077918b3e11c55ebde483223d677c92" }, "downloads": -1, "filename": "django_crossdomainmedia-0.0.2-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "a166b4ad94131ce6a3a29808c9e0784e", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 6877, "upload_time": "2019-09-06T15:17:54", "url": "https://files.pythonhosted.org/packages/b2/9b/ba138070d901cae3ca05dc7e57d5631b88eb47af0c03318343e1a5f66bfb/django_crossdomainmedia-0.0.2-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "dc8930e8b36f2382bc0a7ce71261d8c8", "sha256": "b8a23b71fd909f6554c9809e62e63d10579c76d7340a46200e7f09d8f5607df6" }, "downloads": -1, "filename": "django-crossdomainmedia-0.0.2.tar.gz", "has_sig": false, "md5_digest": "dc8930e8b36f2382bc0a7ce71261d8c8", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5308, "upload_time": "2019-09-06T15:18:12", "url": "https://files.pythonhosted.org/packages/d9/6e/9525b3cf47f08849af8e7f1610507a610d91fd2e9c4e50722bab4c6b3321/django-crossdomainmedia-0.0.2.tar.gz" } ], "0.0.3": [ { "comment_text": "", "digests": { "md5": "49361759f46c334197f876a026f3feba", "sha256": "798bcfe52c853121d060ff9fb1c69fa29e391c4edfe62fc2de275baa61ac53d0" }, "downloads": -1, "filename": "django_crossdomainmedia-0.0.3-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "49361759f46c334197f876a026f3feba", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 6902, "upload_time": "2019-09-06T15:34:27", "url": "https://files.pythonhosted.org/packages/6f/92/6a69839f74ea41ff6f2b0e27178bd124c75a59e7275c9b9ac310aa4a69e2/django_crossdomainmedia-0.0.3-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "df687a52d2cde313a7eb64a0b7641915", "sha256": "25adebf407b0406d17024bbdf8f59c022de2ba7d9a1b4689a63b4b173b410d4b" }, "downloads": -1, "filename": "django-crossdomainmedia-0.0.3.tar.gz", "has_sig": false, "md5_digest": "df687a52d2cde313a7eb64a0b7641915", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5341, "upload_time": "2019-09-06T15:34:06", "url": "https://files.pythonhosted.org/packages/95/18/0e758e8021fd11b7337c3fd7e3133a9b0e86eb4366eb922e0d69f4d804d7/django-crossdomainmedia-0.0.3.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "49361759f46c334197f876a026f3feba", "sha256": "798bcfe52c853121d060ff9fb1c69fa29e391c4edfe62fc2de275baa61ac53d0" }, "downloads": -1, "filename": "django_crossdomainmedia-0.0.3-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "49361759f46c334197f876a026f3feba", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 6902, "upload_time": "2019-09-06T15:34:27", "url": "https://files.pythonhosted.org/packages/6f/92/6a69839f74ea41ff6f2b0e27178bd124c75a59e7275c9b9ac310aa4a69e2/django_crossdomainmedia-0.0.3-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "df687a52d2cde313a7eb64a0b7641915", "sha256": "25adebf407b0406d17024bbdf8f59c022de2ba7d9a1b4689a63b4b173b410d4b" }, "downloads": -1, "filename": "django-crossdomainmedia-0.0.3.tar.gz", "has_sig": false, "md5_digest": "df687a52d2cde313a7eb64a0b7641915", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5341, "upload_time": "2019-09-06T15:34:06", "url": "https://files.pythonhosted.org/packages/95/18/0e758e8021fd11b7337c3fd7e3133a9b0e86eb4366eb922e0d69f4d804d7/django-crossdomainmedia-0.0.3.tar.gz" } ] }