📄

書類管理ウェブシステム構築(1): サーバサイド環境構築・LDAP ログイン

2020/10/04に公開

家にある書類たち,管理はめんどくさいし,参照するときに探したりするのは手間だし,最近 PDF 交付なども増えてるし,せっかくスキャナ付き複合機あるし,NAS もあるので,お手製書類管理ウェブシステムを作成します。

今回は第1回として django の開発環境の構築と LDAP 認証の対応までを記録として残しておきます。

フレームワークのインストール

今回は django を用いて構築します。
また,django rest framework を使うためインストールします。
合わせて便利そうなので django-filter, django-extensions, django-model-utils もインストールします。

$ pipenv --python 3.8
$ pipenv install django djangorestframework django-filter django-extensions werkzeug django-model-utils

project の作成

プロジェクトを作成します。
デフォルトのやり方だと,[プロジェクト名]/[プロジェクト名] ディレクトリに設定ファイルが生成されわかりづらいため,下記のような手順でセットアップし [プロジェクト名]/config ディレクトに設定ファイルが生成されるようにします。

$ mkdir docms
$ cd docms
$ pipenv run django-admin startproject config .

忘れる前に設定ファイル docms/config/settings.py を変更します。
django-extensions を有効化します。
また,SECRET_KEY と DEBUG は環境変数などで適切に扱えるようにしましょう。

ローカライズ設定も忘れずに。

docms/config/settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
+    'django_extensions',
]

...

- LANGUAGE_CODE = 'en-us'
+ LANGUAGE_CODE = 'ja-jp'

- TIME_ZONE = 'UTC'
+ TIME_ZONE = 'Asia/Tokyo'

linter/formatter/test の準備

python の linter, formatter とテストの際にカバレッジ計算するためのライブラリをインストールしましょう。

$ pipenv install --dev flake8 autopep8 coverage mypy pydocstyle

flake8 と coverage の設定ファイルを用意します。

tox.ini:

.flake8
[flake8]
exclude = .venv

[coverage:run]
omit = */tests/*,.venv/*

[coverage:html]
directory = cover

エディタの設定

今回は Visual Studio Code を使用します。
まずは,拡張の Python, Docker, Python Docstring Generator をインストールします。

次に設定ファイル .vscode/settings.json を用意します:

.vscode/settings.json
{
    "python.pythonPath": ".venv/bin/python3.8",
    "python.linting.enabled": true,
    "python.linting.lintOnSave": true,
    "python.linting.pylintEnabled": false,
    "python.linting.flake8Enabled": true,
    "python.linting.flake8Args": [
        "--max-complexity=10"
    ],
    "python.formatting.provider": "autopep8",
    "python.formatting.autopep8Args": [
        "--aggressive", "--aggressive",
    ],
    "autoDocstring.docstringFormat": "numpy",
}

追記
Pylance が話題になっていたので,追加で導入しました。

カスタム User モデルの作成

User は後々の拡張などに備え,django 標準の物を継承して作成したモデルを用いることが推奨されています。
AbstractBaseUser を継承するパターンと AbstractUser を継承するパターンがありますが,今回は難易度の比較的低い AbstractUser を継承したクラスを用います。

まずはアプリを作成します:

$ pipenv shell
$ cd docms
$ ./manage.py startapp users

その後,各ファイルを用意します。

docms/users/models/user.py:

docms/users/models/user.py
import uuid

from django.contrib.auth.models import AbstractUser
from django.db import models


class User(AbstractUser):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)

docms/users/models/__init__.py:

docms/users/models/__init__.py
from .user import User  # noqa

docms/users/admin.py:

docms/users/admin.py
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin

from .models import User

admin.site.register(User, UserAdmin)

id の UUID 化は django-model-utils を使う方法もありますが,今回は愚直に設定しました。

今回,モデルはディレクトリを作成し,その中で管理することとしたので models.py を削除しましょう:

$ rm docms/users/models.py

その後,設定ファイル docms/config/settings.py を書き換えます:

docms/config/settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'django_extensions',
+    'users',
]

...

+ AUTH_USER_MODEL = 'users.User'

ここまできたらまずはマイグレーションファイルを作成します。
このマイグレーションファイルはコマンドで作成可能です:

$ pipenv shell
$ cd docms
$ ./manage.py makemigrations

すると自動で docms/users/migrations/0001_initial.py にファイルが生成されるので,軽く目を通すとどういう働きをするファイルか理解できると思います。

ひとまずは簡単に動作を確認したいので,そのまま以下のコマンドを入力します:

$ pipenv shell
$ cd docms
$ ./manage.py migrate

するとデフォルトでは SQLite のファイルが生成されます。
(データベースの設定はそのうちちゃんとやります。)

LDAP 認証の実装

別で LDAP サーバがある環境なので,アカウント認証は LDAP サーバと連携させたいです。

そこで etianen/django-python3-ldap: Django LDAP user authentication backend for Python 3. を用いて,LDAP の情報でログインを行えるようにします。

$ pipenv install django-python3-ldap

インストールができたら settings.pyINSTALLED_APPS'django_python3_ldap' を追加,AUTHENTICATION_BACKENDS("django_python3_ldap.auth.LDAPBackend",) を設定します。
また,settings.py にその他必要な設定を書き込みます。

実際の settings.py を下に示します(LDAP 関連の設定の一部は環境変数を使用するように設定していますがそのまま掲載します):

docms/config/settings.py
...
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
+     'django_python3_ldap',
    'users',
]
...
+ AUTHENTICATION_BACKENDS = ("django_python3_ldap.auth.LDAPBackend",)
...
+ LDAP_AUTH_URL = os.getenv('LDAP_AUTH_URL')
+ LDAP_AUTH_USE_TLS = True\
+     if os.getenv('LDAP_AUTH_USE_TLS')\
+     and os.getenv('LDAP_AUTH_USE_TLS') in ['true', 'True']\
+     else False
+ LDAP_AUTH_SEARCH_BASE = os.getenv('LDAP_AUTH_SEARCH_BASE')
+ LDAP_AUTH_OBJECT_CLASS = os.getenv('LDAP_AUTH_OBJECT_CLASS')
+ 
+ LDAP_AUTH_USER_FIELDS = {
+     "username": "cn",
+     "first_name": "givenName",
+     "last_name": "sn",
+     "email": "mail",
+ }

LDAP の設定の詳しい内容やここにはない設定は etianen/django-python3-ldap > Available settings を確認してください。

LDAP アカウントの管理者ユーザ化

通常であれば,python manage.py createsuperuser を用いて管理者ユーザ(スーパユーザ)を作成するところですが,今回は LDAP 認証を用いてログインを行い,その username に基づいて管理者ユーザかどうかを判別できるようにします。

と言ってもやり方は簡単です。
以下のコマンドを実行してください (<username> は管理者ユーザの username を指定する):

$ pipenv shell
$ cd docms
$ ./manage.py ldap_sync_users
$ ./manage.py ldap_promote <username>

実行に成功したら,LDAP サーバへの接続が成功しており,指定ユーザを管理者ユーザに設定完了しています。

下のコマンドでサーバを起動したのち,http://127.0.0.1:8000/admin/login/ にアクセスをして上で指定したユーザでログインがうまくいくか確認しましょう。

$ pipenv shell
$ cd docms
$ ./manage.py runserver

参考

Discussion