django adminをall-authのライブラリとkeycloakで認証し、SSOする動作確認を行った備忘録になります。
こちらの記事を参考にさせていただきました。
ディレクトリ
├── demo1 │ ├── Dockerfile │ ├── requirements.txt ├── demo2 │ ├── Dockerfile │ └── requirements.txt └── docker-compose.yml
requirements.txt
Django==5.1.2 django-allauth==65.3.1 django-allauth[socialaccount]==65.3.1
dockerを用いて検証用環境を作成していきます。django, keycloakのdockerは以下を参考にしました。
また、コンテナ<->ホスト<->コンテナ間の通信を、host networkingの機能を用いてlocalhostで接続できるようにします。
Warning
Host networkは現時点でMacのDocker Desktopでは使用できませんのでご注意ください
詳細: https://docs.docker.com/engine/network/drivers/host/
dockerfile定義
FROM python:3 ENV PYTHONUNBUFFERED 1 RUN mkdir /code WORKDIR /code ADD requirements.txt /code/ RUN pip install -r requirements.txt ADD . /code/
docker-compose定義
version: "3.8" services: demo1: build: context: ./demo1 command: python3 manage.py runserver 0.0.0.0:8000 volumes: - ./demo1:/code # host networkingを使用する network_mode: "host" demo2: build: context: ./demo2 command: python3 manage.py runserver 0.0.0.0:8001 volumes: - ./demo2:/code network_mode: "host" keycloak: image: quay.io/keycloak/keycloak:26.1.0 container_name: keycloak command: start-dev environment: - KC_BOOTSTRAP_ADMIN_USERNAME=admin - KC_BOOTSTRAP_ADMIN_PASSWORD=admin volumes: - keycloak_data:/opt/keycloak/data network_mode: "host" volumes: keycloak_data:
ビルド後、djangoの諸々のコマンドを実行します。
$ docker-compose run demo1 django-admin startproject config . $ docker-compose run demo1 python manage.py startapp demo $ docker-compose run demo2 django-admin startproject config . $ docker-compose run demo2 python manage.py startapp demo
今回モデルは既存のUserを使うのでmigrateも済ませます
$ docker-compose run demo1 python manage.py migrate $ docker-compose run demo2 python manage.py migrate
keycloak側の準備をします。行うこととしては各demo用のclientの作成と、認証に使用するUserの作成になります。
PRで使用するClient情報をClients->Create clientから作成します。
作成後、Valid redirect URIsにhttp://localhost:8000/accounts/oidc/keycloak/login/callback/
を入力します。
demo2側も同様に作成します。
認証に使用するUserをUsers->Add userから作成します。
作成後、Credencials->Set passwordからパスワード情報を作成します。
以下all-authのドキュメントを参考にdemo1, demo2どちらにもall-authでkeycloakを使用できるように設定を行います。
# settings.py INSTALLED_APPS = [ ... 'demo', "allauth", "allauth.account", "allauth.socialaccount", "allauth.socialaccount.providers.openid_connect", ] MIDDLEWARE = [ ... "allauth.account.middleware.AccountMiddleware", ] TEMPLATES = [ { # demo1だけでok 'DIRS': [ BASE_DIR / "templates", ], }, ] AUTHENTICATION_BACKENDS = [ 'django.contrib.auth.backends.ModelBackend', 'allauth.account.auth_backends.AuthenticationBackend', ] SOCIALACCOUNT_PROVIDERS = { "openid_connect": { "APPS": [ { "provider_id": "keycloak", "name": "Keycloak", "client_id": "demo1", # 先ほど作成したClientのシークレット "secret": "sZgw6WF7i5Xr2a0sXq6HTyzhSKOcopPB", "settings": { "server_url": "http://localhost:8080/realms/master/.well-known/openid-configuration", }, } ] } } # あるとall-authのformでsocialのみになるので設定 ACCOUNT_EMAIL_VERIFICATION = 'none' SOCIALACCOUNT_ONLY = True # adapterをカスタマイズする SOCIALACCOUNT_ADAPTER = 'demo.adapters.CustomSocialAccountAdapter' # session名被るのでどちらかのみ変更 SESSION_COOKIE_NAME = 'demo2'
django-adminの認証もkeycloakを用いたいため、demoアプリ側のurlのinclude含め、config/urlsの設定を以下に変更します。
from django.contrib import admin from django.urls import path, include from allauth.account.decorators import secure_admin_login admin.autodiscover() admin.site.login = secure_admin_login(admin.site.login) urlpatterns = [ path("", include("demo.urls", namespace="demo")), path("accounts/", include("allauth.urls")), path('admin/', admin.site.urls), ]
keycloakで認証後のUser生成でis_superuser周りをTrueにしたいため、adapterを用いてカスタマイズします
# demo/adapters.py from allauth.socialaccount.adapter import DefaultSocialAccountAdapter class CustomSocialAccountAdapter(DefaultSocialAccountAdapter): def save_user(self, request, sociallogin, form=None): user = super().save_user(request, sociallogin, form) user.is_superuser = True user.is_staff = True user.save() return user
demo1側はdjango templateでdemo1, demo2どちらのadminにも遷移できる画面を生成します。
# demo/View from django.contrib.auth.mixins import LoginRequiredMixin from django.views.generic import TemplateView class DemoView(LoginRequiredMixin, TemplateView): template_name = "demo.html"
demo.htmlのテンプレートを作成します。
<html> <body> <a href="{% url 'admin:index' %}">Go to demo1 admin</a> <br /> <a href="http://localhost:8001/go-to-admin/">Go to demo2 admin</a> <br /> </body> </html>
keycloakのデフォルトだと、keycloakの認証画面の前にテンプレートを挟むので、そのままkeycloakの認証にリダイレクトするように設定します。
# demo/view from django.views.generic.base import View from allauth.socialaccount.providers.openid_connect.views import OpenIDConnectOAuth2Adapter class GoToAdminView(View): def get(self, *args, **kwargs): return OpenIDConnectOAuth2Adapter(self.request, provider_id='openid_connect').get_provider().redirect(self.request, process='login', next_url='/admin')
# urls from django.urls import path from .views import GoToAdminView app_name = "demo" urlpatterns = [ path("go-to-admin/", GoToAdminView.as_view(), name="go-to-admin") ]
dockerを立ち上げて、http://localhost:8000にアクセスします。
SignIn->Keycloak->Continueからkeycloakの認証画面に遷移します。
作成したUser情報を入れて認証したのち、表示されているGo to demo1 admin
でdemo1側のadminに遷移します。
http://localhost:8000 に戻りGo to demo2 admin
をクリックし、demo2側に遷移しても、そのままdemo2のdjango adminが表示されます。
all-authがとても良しなにOIDC認証周りを行ってくれるなと思いました。
テンプレート画面から複数のdjano adminのSSOをイメージできたので、今回はここまでにします。
コードはgithubに上げてあります。