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を書き換えてみる。