クライアントシークレットなしのCognitoユーザプールをDjangoで使う方法
はじめに
Djangoの認証にCognitoを使う場合、いくつかライブラリが提供されているが、Django3.x非対応だったり、DRFベースだったりしてフロントエンドで使うためのものとしては選択肢が少ない。
django-cognito-reduxは上記案件に対応している貴重なライブラリである。
ただし、ユーザープールのアプリクライアントでシークレットキーを設定することが前提条件となっているため、他のウェブアプリで共有したい場合ネックとなる。
今回、関数のオーバライドによりクライアントキーなしでも利用できるようにしてみた。
対象読者
- 認証基盤にAWS Cognitoを使っている方
- DjangoおよびVue.jsなどJavascript系のウェブフレームワークのフロントエンド開発者
環境
- Python-3.9.6
- Django-3.2.5
- django-cognito-redux-1.4.5
セットアップ
- Python-3.9.6
- Django-3.2.5
- django-cognito-redux-1.4.5
セットアップ
GithubのレポジトリにソースがあるのでREADME.mdに従って設定する。
動作確認
Djangoのアプリケーションを起動しブラウザでhttp://localhost:8000/
にアクセスする。
特に問題がなければ管理画面http://localhost:8000/admin/
にアクセスする。
Cognitoユーザプールの既存アカウントでログインしてみる。
ログインに成功すると管理画面のダッシュボードが表示される。
このサンプルではCognitoユーザにパーミッションを与えていないので特に何も表示されないがログインは成功した。
この後、ログアウトして管理者(create superuser
で作成したユーザ)で再度ログインする。
すると管理者以外にCognitoのユーザが追加されている。
email
、firstname
およびlastname
はCognitoのユーザ情報から取得して登録している。
解説
今回のサンプルは認証のみ行っている。
スクラッチから作る場合はまず手動でプロジェクト配下にaccount
ディレクトリを以下の構成で作る。
account/
├── __init__.py
├── backends.py
└── helpers.py
backends.pyに認証バックエンドを定義する。
class AwsCognitoAuthentication:
def authenticate(self, request, username=None, password=None):
if username is None:
user, _, _ = m_helpers.process_request(request)
return user
else:
try:
result = initiate_auth(
{
'username': username,
'password': password,
'auth_flow': 'USER_PASSWORD_AUTH'
}
)
# ...
initiate_auth
関数はクライアントシークレットの有無で使い分けたいので、冒頭で振り分けている。
if getattr(settings, 'APP_SECRET_KEY'):
# クライアントシークレットがあるとき
from django_cognito.authentication.cognito.helpers import initiate_auth
else:
# ないとき
from .helpers import initiate_auth
helpers.pyはオリジナルを改変して以下のようにする。
def initiate_auth(data, param_mapping=None):
if ('username' in data and 'password' in data) \
or ('username' in param_mapping and 'password' in param_mapping):
auth_flow = constants.USER_PASSWORD_FLOW
username = parse_parameter(data, param_mapping, 'username')
password = parse_parameter(data, param_mapping, 'password')
return initiate_auth_without_secret(username, auth_flow, password)
else:
raise ValueError('Unsupported auth flow')
def initiate_auth_without_secret(username, auth_flow, password=None,
refresh_token=None, srp_a=None):
auth_parameters = {}
# ...
上記ができたらsettings.pyに設定を加える
# ...
INSTALLED_APPS = [
'django.contrib.admin',
# ...
'account',
]
# ...
# backend
AUTHENTICATION_BACKENDS = [
'django.contrib.auth.backends.ModelBackend',
'account.backends.AwsCognitoAuthentication',
]
# ...
まとめ
今回のキモとなっているのはオリジナルのactions.pyの以下の行
def initiate_auth(username, auth_flow, password=None, refresh_token=None, srp_a=None):
auth_parameters = {'SECRET_HASH': utils.get_cognito_secret_hash(username)}
ここでCognitoに渡すパラメータとしてSECRET_HASH
を必須としている。なので
def initiate_auth(username, auth_flow, password=None, refresh_token=None, srp_a=None):
auth_parameters = {}
とした。もちろんこのままではクライアントシークレットがある場合は認証できないので呼び出す関数を使い分けている。
Author And Source
この問題について(クライアントシークレットなしのCognitoユーザプールをDjangoで使う方法), 我々は、より多くの情報をここで見つけました https://qiita.com/higebobo/items/6e1d9995a4c78896c2f4著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .