はじめに
Djangoで作成したアプリケーションはEmailアドレスをIDとして、LDAPで認証する仕組みにしています。
ユーザーIDはあらかじめ分かっているわけですが、アプリケーション内部で許可権限をグループなどのユーザーリストで管理したい場合、デフォルトの管理画面(django.contrib.admin)で追加できるのはDjangoにログインして、DB上に登録されているユーザーIDのみです。
つまり最初にログインしてもらってから、権限付与の作業をしていたのですが、まぁUXの観点からはログイン時点で適切な権限が付与されていないと当然まずいわけで、あらかじめユーザーIDを登録しておきたいと思いました。
アプリケーション上で利用したい主なユーザーグループはLDAPのGroupで管理しているメンバーと同一なので、バルクでユーザーIDの登録だけを行う機能を追加しました。
環境
- Django 3.2.18
- requests 2.28.2
requestsはLDAPクライアントではなくREST APIを通してグループリストがダウンロードできるようになっているので、そのAPIにアクセスするためのクライアントライブラリです。
実装のポイント
個別のケースで再利用ができる、できないなどがあると思うので、ユーザーIDをDjangoのDBに登録するための考慮点をまとめておきます。
ユーザー追加用のUIを追加
superuserだけが利用するためのAppを追加しました。
- ./myapp/admintool/ ディレクトリ
- ./templates/admintool/list.html テンプレートファイル
myadpp/admintool/ 以下には、空の init.py ファイルの他は、views.py と urls.py だけを配置しています。
from django.urls import path, include
from .views import AdminToolView
urlpatterns = [
path('', AdminToolView.as_view(), name='admintool_usermanage')
]
ユーザーID登録の基本的なコード
views.pyに追加するコードは次のような内容です。
from myapp.authenticate.models import AuthUser
from django.views.generic import ListView
from django.contrib.auth import get_user_model
from django.urls import reverse_lazy
class AdminToolView(ListView):
model = GroupMembers
template_name = "admintool/list.html"
def dispatch(self, request, *args, **kwargs):
if request.user.is_superuser:
...
pass
else:
return redirect(reverse_lazy('top'))
if request.method == "POST" and ... :
glname = request.POST.getlist('glname')
r = requests.get("https://....somewhere..../..rest_api../%s" % (glname))
...
User = get_user_model()
User.objects.create_user(email="%s" % (member_info['email']),
family_name=member_info['name'].split(' ',1)[0],
first_name=member_info['name'].split(' ',1)[1],gender='na',
phone="%s" % (member_info['phone'].split(' ')[0]),
password='hogehoge')
...
return redirect(reverse_lazy('admintool_usermanage')) ## returning by GET method
return super().dispatch(request, *args, **kwargs) ## when method != "POST"
テンプレート上のformからPOSTで渡されたグループ名を元にユーザーリストを抽出し、その数だけユーザーIDを追加するループを回します。
ここでget_user_model()から返されるのは、この環境では カスタム・ユーザー・モデルを定義しているmyapp.authenticate.models.AuthUser です。
直接呼び出してもget_user_model()経由で間接的に呼び出しても、最終的にはobjects.create_user()によってIDを登録することができます。
User.objects.filter()を利用すれば、登録済みかどうか判定することができます。
create_user()では自分がAuthUserに定義した要素を指定しますが、passwordがNoneオブジェクトのままだとエラーになります。LDAPで認証する際にはpasswordはハッシュ化された文字列が保存されるものの利用されませんのでダミーの文字列(実際には適切な乱数から生成した文字列)を指定します。
適当なユーザーIDのリストをrequests経由で取得してコードを反映しています。
これぐらいの操作で、あらかじめDBに登録しておきたいユーザーを追加することができました。