目的
Djangoのadminページのログイン画面の前にbasic認証をかけたかった。でも他のページにはかけたくなかった。
Djangoはもちろんpythonも詳しくわかってないけどとりあえずできたっぽいから晒してみる。
最適解とは思ってないので、もっといい方法があったら教えてください。
python: 3.5.2
Django==1.11.4
丸2日間くらいすげー試行錯誤した結果できたものは超シンプルというなんとも言えないこの感じ。
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()
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)
]
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の明確な違いがないのがいいところでもあり悪いところでもある気がします。