python-social-auth + social-auth-app-django を使ってログインシステムを構築している場合、OAuth プロバイダーにリダイレクトする際にクエリパラメーターに redirect_uri パラメーターを付与し、認証完了後にそのURLに戻ってきます。
その時、サーバーの構成によっては redirect_uri の URL のスキームが、本来 https:// でなければならない所が http:// になって困ることがあります。逆に PC で開発している時は、今度は http:// になって欲しい箇所が https:// になって困ることもあります。
それらのコントロールをする際、どのような設定をすればいいか、どこを見ればいいかを書いておきます。
平文の URIに戻される理由
サーバーシステムが全て https:// なのに、 redirect_uri のスキームが平文の http:// になる場合があります。
この原因は、システムの途中のリバースプロキシが https をデクリプトし、平文 http にしてバックエンドサーバーにリクエストするためです。
Django はそれを平文http のリクエストとして受け付けるため、平文 http リダイレクトURLを生成します。
django.core.handlers.wsgi.WSGIRequest の _get_scheme で行っています。
対策
A. SECURE_PROXY_SSL_HEADER を使う
settings に
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
と書いておけば、リクエストヘッダーに X-Forwarded-Proto: https が含まれてた場合、リダイレクトのスキームを https:// にします。
使用箇所は、 django/http/request.py の HttpRequest.scheme プロパティを見てください。
注意点として、この設定の2項目目の 'https' は、「X-Forwarded-Proto ヘッダーが無かった時のデフォルトのスキーム」ではありません。
X-Forwarded-Proto ヘッダーが、この値と一致した時は https になり、不一致の時は http になります。
そのため、もし
SECURE_PROXY_SSL_HEADER = ('HTTP_X_REDIRECT_URL_IS_HTTPS', '1')
という設定にした場合は、リクエストヘッダーが X-Redirect-Url-Is-Https: 1 となっていた場合に https となり、それ以外は http となります。
B. SOCIAL_AUTH_REDIRECT_IS_HTTPS を使う
social_core/strategy.py の BaseStrategy.absolute_uri() を見ると、Django の settings に
SOCIAL_AUTH_REDIRECT_IS_HTTPS = True
もしくは
REDIRECT_IS_HTTPS = True
と書くと、ログイン時の redirect_uri のスキームを強制的に https に書き換えれることがわかります。
*_REDIRECT_IS_HTTPS この prefix は、ライブラリの使い方によって変化しますのでご注意ください。
C. 認証バックエンドの get_redirect_uri をオーバーライドする
social.backends.oauth.BaseOAuth2 等を継承して、独自の認証バックエンドを作って使っている場合は、get_redirect_uri メソッドをオーバーライドしても良いと思います。
def get_redirect_uri(self, state=None):
uri = super().get_redirect_uri(state)
# ここで、条件によって URL スキームを文字列置換
return uri
D. 独自 Strategy の absolute_uri をオーバーライドする
social_core.strategy.BaseStorategy を継承した独自の Strategy を作って使っている場合は、 absolute_uri メソッドをオーバーライドすることでURIスキームを自由にコントロールできます。
E. django.core.handlers.wsgi.WSGIRequest の _get_scheme をパッチする
絶対URLを生成する際、リクエストのスキームの判定のため django.http.request.HttpRequest.scheme や、もしくはそこから django.core.handlers.wsgi.WSGIRequest の _get_scheme がコールされます。少し強引ですがそこをパッチして、返すスキームをコントロールすることができます。
例えば、下記のようにパッチすれば、絶対URLを作る時はデフォルトで https スキームになります。
from django.core.handlers.wsgi import WSGIRequest
def _get_scheme(self):
return 'https'
WSGIRequest._get_scheme = _get_scheme
また、下記のようにパッチをすれば settings の値で動作を変えられます。
from django.core.handlers.wsgi import WSGIRequest
from django.conf import settings
def _get_scheme(self):
return getattr(settings, 'ABSOLUTE_URL_SCHEME', 'https')
WSGIRequest._get_scheme = _get_scheme
この場合、social-auth-app-django + python-social-auth に限らず、広い範囲で絶対URL を作る際に適用されますのでご注意ください。
また、 django.core.handlers.wsgi は django.core.settings をインポートしていますので、 django.core.settings の評価後でないとパッチできません。メイン app の app.py や url.py の評価時にパッチすれば良いと思います。