diadia

興味があることをやってみる。自分のメモを残しておきます。

emailとpasswordで認証する仕組みにする

他の方法も

下記の記事はUserモデルを独自のモデルにして識別子(identifier)をemailにすることで認証をemailで行うように実装する方法だ。 他方で認証バックエンドにカスタムバックエンドを準備し、それを使うことでEmail認証する方法も成功したのでそのうち記事を書きたい。とりあえずリポジトリだけ上げておく。

authentication_backends_sample

 

ドキュメント:https://docs.djangoproject.com/ja/2.1/topics/auth/customizing/

EmailとPasswordで認証するために

方針はdjangoのUserモデルを書き換えemailとpasswordで認証する。
Userモデルは以下から構成される。

  • AbstractUser
  • AbstractBaseUser
  • PermissionsMixin

これらのモデルを継承し、自分に都合の良いモデルを作成するわけだけど、なぜ継承するのか? それはdjangoの特徴に関係している。djangoの特徴はユーザー認証が予め提供されていることである。djangoのユーザ認証をの仕組みを利用しつつ開発すれば、認証技術については早く、精度の高いものが出来上がる。だから継承という手続きをとる。

また認証ではusernameは不要なので存在すれば消去する。

AbstractBaseUserはどうなっているか

属性だけ見れば以下のようになっている。

class AbstractBaseUser(models.Model):
    password = models.CharField(_('password'), max_length=128)
    last_login = models.DateTimeField(_('last login'), blank=True, null=True)

    is_active = True

emailフィールドがないのでemailフィールドを付け加えれば、emailとpasswordで完成しそうだ。ただし、PermissionsMixinを統合させる前のモデルなのでPermissionsMixin の機能がないことがデメリットだ。これを自分で補うことになりそうだ。

AbstractUserはどうなっているか

属性だけ見れば以下のようになっている。

class AbstractUser(AbstractBaseUser, PermissionsMixin):
    """
    An abstract base class implementing a fully featured User model with
    admin-compliant permissions.
    Username and password are required. Other fields are optional.
    """
    username_validator = UnicodeUsernameValidator()

    username = models.CharField(
        _('username'),
        max_length=150,
        unique=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'), max_length=30, blank=True)
    last_name = models.CharField(_('last name'), max_length=150, blank=True)
    email = models.EmailField(_('email address'), blank=True)
    is_staff = models.BooleanField(
        _('staff status'),
        default=False,
        help_text=_('Designates whether the user can log into this admin site.'),
    )
    is_active = models.BooleanField(
        _('active'),
        default=True,
        help_text=_(
            'Designates whether this user should be treated as active. '
            'Unselect this instead of deleting accounts.'
        ),
    )
    date_joined = models.DateTimeField(_('date joined'), default=timezone.now)

    objects = UserManager()

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

emailのフィールドがすでに存在している。これではユーザ認証に役立たないので上書き修正する必要があるようだ。emailにはユニークオプションをつけたい。usernameが存在しているので、ここを修正したい。またUSERNAME_FIELD = 'username'となっているのでusernameがログイン時に必要となってしまう。これをUSERNAME_FIELD = 'email'に書き換える事が必要。

 

どちらのモデルを利用するか

PermissionsMixin関係が複雑そうなので、すでに統合されているAbstractUserを書き換えてみる。