LoginSignup
7
8

More than 5 years have passed since last update.

python初心者がDjangoのadminにbasic authをつけてみる

Last updated at Posted at 2017-08-12

目的

Djangoのadminページのログイン画面の前にbasic認証をかけたかった。でも他のページにはかけたくなかった。
Djangoはもちろんpythonも詳しくわかってないけどとりあえずできたっぽいから晒してみる。
最適解とは思ってないので、もっといい方法があったら教えてください。

python: 3.5.2
Django==1.11.4

丸2日間くらいすげー試行錯誤した結果できたものは超シンプルというなんとも言えないこの感じ。

yourproject/my_admin_site.py
from django.http import HttpResponse
from django.views.decorators.cache import never_cache
from django.contrib.admin.sites import site, AdminSite
import base64

class MyAdminSite(AdminSite):

    def __init__(self, name='admin'):
        super().__init__()

    def get_urls(self):
        self._registry = site._registry
        return super().get_urls()

    @never_cache
    def login(self, request, extra_context=None):
        if not self._basicAuth(request):
            return self._http401()
        return super().login(request, extra_context)

    def _basicAuth(self, request):
        if 'HTTP_AUTHORIZATION' not in request.META:
            return False
        (authscheme, base64_idpass) = request.META['HTTP_AUTHORIZATION'].split(' ', 1)
        if authscheme.lower() != 'basic':
            return _http401()
        idpass = base64.decodestring(base64_idpass.strip().encode('ascii')).decode('ascii')
        (id_, password) = idpass.split(':', 1)
        if id_ == "foo" and password == "bar":
            return True
        else:
            return False

    def _http401(self):
        response = HttpResponse("Unauthorized", status=401)
        response['WWW-Authenticate'] = 'Basic realm="basic auth test"'

        return response


my_site = MyAdminSite()

yourproject/urls.py
from django.conf.urls import url, include
from yourproject import my_admin_site

urlpatterns = [
    #url(r'^admin/', admin.site.urls),
    url(r'^admin/', my_admin_site.my_site.urls)
]

こんな感じです。
スクリーンショット.png

yourproject/my_admin_site.py
    def get_urls(self):
        self._registry = site._registry
        return super().get_urls()

この部分がなくてもbasic認証はできるのですが、これがないとadminに入った時なんの操作もできないという悲しい画面が現れます。
操作できるモデルの一覧はdjango.contrib.admin.sites.siteの_registerに外部から登録されていくので、モデルを継承しただけだとその情報までは引っ張ってくることができないっぽい?
ので、自前のクラスのself._registerにdjango.contrib.admin.sites.site._registerをコピーすることで解決。する気がする。
暗黙のprivateメソッドにアクセスするという嫌な感じですがこれでうまくいきました。多分。今の所不都合はありません。

python, publicとprivateの明確な違いがないのがいいところでもあり悪いところでもある気がします。

参考 https://bitstar.jp/blog/basic%E8%AA%8D%E8%A8%BC

7
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
8