Djangoでプロジェクト全体に独自のBasic認証をかける方法

Djangoのプロジェクトを使っていてBasic認証をかける方法はいくつかあると思うが、今回は「django-basicauth」を利用する。

https://pypi.org/project/django-basicauth/

基本的にはドキュメントにあるようにViewごとにデコレータを付けるかミドルウェアでプロジェクト全体にBasic認証をかけることができる。(どちらもimportして必要な記述を足すだけなので非常に簡単)

しかし場合によっては認証をかけるか、かけないかを細かく設定したい時がある(例えばテストやAPIなどではBasic認証をかけたくないなど)。このような時には既存のコードを少し修正する必要がある。今回はミドルウェアを使ってページ全体にBasic認証をかけるが基本的にはデコレータを使う場合も同様の修正をすれば良い。

ライブラリのソースコードを見ると以下のようにDjangoミドルウェアを実装していた。

class BasicAuthMiddleware(MiddlewareMixin):
    def process_request(self, request):
        if not validate_request(request):
            return HttpResponseUnauthorized()
        return None

django-basicauth/middleware.py at master · hirokiky/django-basicauth

ミドルウェアについては以下を参照:https://office54.net/python/django/django-middleware-about#section1-1

このミドルウェアでprocess_requestというメソッドが呼ばれているが、Djangoの公式ドキュメントを参照すると以下のように書いてある。

https://docs.djangoproject.com/en/4.1/topics/http/middleware/#upgrading-pre-django-1-10-style-middleware

The __call__() method:

  1. Calls self.process_request(request) (if defined).
  2. Calls self.get_response(request) to get the response from later middleware and the view.
  3. Calls self.process_response(request, response) (if defined).
  4. Returns the response.

ミドルウェアではリクエストごとに__call__()メソッドがフックされるがprecess_requestが定義されている場合はViewを呼び出す前に実行してくれる。

そのため上のライブラリのソースコードではprecess_requestをオーバーライドしてvalidate_requestメソッドで認証のチェックを行っている。

以上のようにライブラリがBasic認証をかけていることが分かったのでもし追加の機能を加えたい場合は以下のようにすればよい。

class BasicAuthMiddleware(MiddlewareMixin):

    def process_request(self, request):

    # 追加
        # テストの時にはBasic認証をかけない
        if TESTING:
            return None
            
    # ライブラリと同じ
        if not validate_request(request):
            return HttpResponseUnauthorized()

        return None

以上に加えてsettins.pyにBasic認証の設定を記述する。