0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

DjangoでEメールIDでログインする時に、'@'を含むか検証させたい

Posted at

はじめに

Djangoを使っていて違和感を感じたのは、EメールアドレスをログインIDにすることはデフォルトの挙動ではないという点でした。どちらかを選択するという考えでもないようで、簡単に切り替える方法は提供されていません。

これを解決するために、強力な汎用機能である"Custom User Model"を利用する方法は様々なところでガイドされています。

問題は、そこからログインページで、ID、パスワードを入力する際に、IDが'@'文字を含まない場合でも処理が進んでしまうことでした。

Custom User Modelを利用している前提で、IDにドメイン名を含まない場合に、処理を進めないようにしてみたいと思います。

技術的な問題点

EメールをIDとして利用できるようになっても、inputタグ自体はusernameのまま変化していません。
usernameとしてはあらゆる文字列が想定されるため、基本的には何でも受け入れてしまいます。

ここで困る事は、ドメイン名(e.g. @example.com)を含まない場合でも、Loginボタンが押下できて、ページ遷移が発生し、無駄に処理(DBやLDAPサーバーとの通信)が発生します。

/accounts/login/ページのHTML抜粋
  <div class="col-12">
    <div class="sm-3">
      <label>E-mail</label>
    </div>
    <div class="sm-4">
      
      <input type="text" name="username" autofocus autocapitalize="none" autocomplete="username" maxlength="254" required id="id_username">
    </div>
  </div>

期待する動作としては、Eメールアドレスの形式に合わない場合には、画面上に警告を出してくれることです。

現在の設定

urls.pyにはカスタマイズしたログインページを表示させたいので、次のような設定が入っています。

myapp/urls.pyからの抜粋
from .forms import RecaptchaLoginForm
...
    path('accounts/login/',
         LoginView.as_view(
             form_class=RecaptchaLoginForm,
         ),
         name='login',
    ),
...

このRecaptchaLoginFormクラスは次のようになっています。

myapp/forms.pyからの抜粋
...
from django.contrib.auth.forms import AuthenticationForm
from captcha.fields import ReCaptchaField

class RecaptchaLoginForm(AuthenticationForm):
    captcha = ReCaptchaField()
    pass
...

ReCaptchaのために、django-recaptcha 3.0.0を利用しています。

変更後のコード

このRecaptchaLoginFormクラスを変更して、親のAuthenticationFormのコードなどを確認すると、usernameフィールドを上書きしてあげればうまく動きそうです。

元のコードを参考に、次のように変更しました。

myapp/forms.pyからの抜粋
...
from django.contrib.auth.forms import AuthenticationForm
from django.forms.fields import EmailField
from django import forms
from captcha.fields import ReCaptchaField

class RecaptchaLoginForm(AuthenticationForm):
    username = EmailField(widget=forms.EmailInput(attrs={'autofocus': True}))
    captcha = ReCaptchaField()
    pass
...

この結果、HTMLは次のように変更されました。

/accounts/login/のHTML抜粋
...
  <div class="col-12">
    <div class="sm-3">
      <label>E-mail</label>
    </div>
    <div class="sm-4">
      <input type="email" name="username" autofocus maxlength="254" required id="id_username">
    </div>
  </div>
...

これによってSubmitボタンを押下した時に検証され、tooltipが表示されPOST処理が停止します。

image.png

マウスオーバー時のテキストも変更されますので、これが一番効果的かもしれません。

image.png

課題

このTooltipは何も表示されないよりは良いですが、autofocusによってブラウザが入力候補を表示してしまうと視認できずにUXが低下します。

今回の方法はフレームワークの手順に従った適切な対応ですが、templates/registration/login.html に次のようなJavaScriptを埋め込む方法も考えられます。

image.png

templates/registration/login.htmlに追加したJavaScriptコード
<script type="text/javascript">
  // validate email input field identified by "#id_username"
  (function () {
      'user strict'
      target = document.querySelector('form[method="post"]');
      target.addEventListener('submit', function(event) {
	  const input_field = document.getElementById('id_username');
	  const emailAddress = input_field.value;
	  if( /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$/.test(emailAddress) != true) {
	      // when invalid
	      event.preventDefault();
	      input_field.style.border = "thin solid red";
          // check existing warning field
	      if (! document.getElementById("myid_email_input_field")) {
		      // show warning text
		      let input_field_element = document.createElement("span");
		      input_field_element.setAttribute("id", "myid_email_input_field");
		      let input_field_content = document.createTextNode("This is not a valid email format.");
		      input_field_element.appendChild(input_field_content);
		      input_field_element.setAttribute("class", "px-3 bg-warning");
		      input_field.after(input_field_element);
	      }
	  }
      });
  })()
</script>

この方法はForm定義を変更した場合には動作しないので、いずれかの方法を選択することになると思います。

さいごに

どんな手段を使っても、クライアント(Webブラウザ)側の検証処理は勝手に変更されたり、バイパスされたりする可能性があるので、サーバー側では、全ての入力を検証する必要があります。

あまり頑張り過ぎても良くないですが、Custom User Modelを使う場合には、ID入力欄の検証処理にも少しは気を配るべきかとは思います。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?