Vasyworksでのユーザ認証について:Vasyworks解説

Vasyworksのユーザ認証では登録系システムのユーザ(主に自社ユーザ)と空室情報閲覧システムのユーザ(主に賃貸仲介業者)のユーザテーブルを別にしたり、Djangoの標準のユーザ認証に別の条件を追加したりしています。下記にmysiteプロジェクトにおけるサンプルコードを記載します。

■users/models.py

"""
System Name: Vasyworks
Copyright (C) 2020 Yasuhiro Yamamoto
"""
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin, UserManager, Group, Permission
from django.contrib.auth.validators import UnicodeUsernameValidator
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from django.core.mail import send_mail


class MyUser(AbstractBaseUser, PermissionsMixin):
    """
    ユーザ
    """
    username_validator = UnicodeUsernameValidator()

    username = models.CharField(
        _('username'),
        db_column='username',
        max_length=150,
        unique=True,
        db_index=True,
        help_text=_('Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.'),
        validators=[username_validator],
        error_messages={
            'unique': _("A user with that username already exists."),
        },
    )
    first_name = models.CharField(_('first name'), db_column='first_name', max_length=30, null=True, blank=True)
    last_name = models.CharField(_('last name'), db_column='last_name', max_length=150, null=True, blank=True)
    email = models.EmailField(_('email address'), db_column='email', null=True, blank=True)
    is_staff = models.BooleanField(_('staff status'), db_column='is_staff', default=False)
    is_active = models.BooleanField(_('active'), db_column='is_active', default=True)
    date_joined = models.DateTimeField(_('date joined'), db_column='date_joined', default=timezone.now)

    #追加項目
    is_company = models.BooleanField(_('is_company'), db_column='is_company', default=False)
    is_company_admin = models.BooleanField(_('is_company_admin'), db_column='is_company_admin', default=False)

    groups = models.ManyToManyField(
        Group,
        verbose_name=_('groups'),
        blank=True,
        help_text=_(
            'The groups this user belongs to. A user will get all permissions '
            'granted to each of their groups.'
        ),
        related_name='user_set',
        related_query_name='user',
    )
    user_permissions = models.ManyToManyField(
        Permission,
        verbose_name=_('user permissions'),
        blank=True,
        help_text=_('Specific permissions for this user.'),
        related_name='user_set',
        related_query_name='user',
    )

    objects = UserManager()

    EMAIL_FIELD = 'email'
    USERNAME_FIELD = 'username'
    REQUIRED_FIELDS = ['email']

    class Meta:
        db_table = 'my_user'
        verbose_name = _('user')
        verbose_name_plural = _('users')

    def clean(self):
        super().clean()
        self.email = self.__class__.objects.normalize_email(self.email)

    def get_full_name(self):
        full_name = '%s %s' % (self.first_name, self.last_name)
        return full_name.strip()

    def get_short_name(self):
        return self.first_name

    def email_user(self, subject, message, from_email=None, **kwargs):
        send_mail(subject, message, from_email, [self.email], **kwargs)

■users/backends.py

"""
System Name: Vasyworks
Copyright (C) 2020 Yasuhiro Yamamoto
"""
from django.contrib.auth.backends import ModelBackend


class MyUserBackEnd(ModelBackend):
    """
    ユーザバックエンド
    """
    def authenticate(self, request, username=None, password=None, **kwargs):
        user = super().authenticate(request, username, password)

    #追加条件
        if user:
            if not user.is_company and not user.is_company_admin:
                return None

        return user

■mysite/settings.py

・・・

# Authorization
AUTH_USER_MODEL = 'users.MyUser'
AUTHENTICATION_BACKENDS = [
    'users.backends.MyUserBackEnd',
]
LOGIN_URL = '/login/'
LOGIN_REDIRECT_URL = '/menu/'
LOGIN_ERROR_URL = '/login/'


・・・

まずはユーザ認証のためのユーザクラスをカスタマイズします。継承元のスーパークラスとしてAbstractUserクラスとAbstractBaseUserクラスがあります。AbstractUserクラスはAbstractBaseUserクラスを継承したクラスです。Django標準のユーザの項目は削除せず、項目を追加するだけならAbstractUserクラスを継承すると簡単にできます。VasywoksではAbstractUserクラスを継承させてもよかったのですが、利用者がカスタマイズしやすいようAbstractBaseUserクラスを継承させています。

次にバックエンドクラスをカスタマイズします。VasyworkssではModelBackendクラスを継承させています。ModelBackendクラスはBaseBackendクラスを継承していて、後述するsettings.pyのAUTH_USER_MODELの設定を利用するバックエンドクラスです。もし、Django標準のユーザ認証と大きく認証方法を変更したい場合はBaseBackendからの継承も必要となるでしょう。VasyworksではModelBackendの認証を実施後、追加で認証処理を入れています。

それからsettings.pyでユーザ認証の設定を記述します。認証ユーザとして使いたいクラスはAUTH_USER_MODELの設定に指定しましょう。また、認証でusernameとパスワード以外の条件を追加するためのユーザバックエンドクラスをAUTHENTICATION_BACKENDSの設定に指定します。Vasyworksでは、合わせてログインページのURLとログイン直後に表示するページのURLを記載しています。ログインに失敗した場合はログインページに戻ってくるようにしています。