1
1

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 3 years have passed since last update.

【Nuxt.js・TailwindCSS】Firebase Authでバリデーションプラグインを使用せずに正規表現でセキュリティ対策(アカウント登録)

Posted at

#はじめに
こんにちは。
こちらの記事では、Firebase Authで正規表現を用いたバリデーションを行う方法を記しています。
誤っている点がございましたらコメントいただけると幸いです。

##なぜ正規表現を使用するのか
Firebase Authでは、「パスワードが5文字以下のとき」や「すでに登録済みのメールアドレスを使おうとしたとき」など、決まった条件に対しては特定のエラーメッセージが返すことができます。

しかし、英字または数字のみでパスワードを登録することができてしまうため、不正ログインされる原因になりかねません。
そこで、英数字を含めないと登録できないように処理を行うため、正規表現を使用します。

##実装手順
今回はアカウント作成画面で、メールアドレスとパスワードで登録できる処理を記述します。(storeのvuexとpuluginsのfirebaseの記述は省略します)

###1. アカウント登録ページの作成
下記のようにシンプルなアカウント登録ページを作成します。
何が行われているか簡単に説明すると、
正常に登録できた場合は、アラートで通知してからstoreでログイン状態をログイン済みに設定、メインページへ遷移する。
エラーが発生した場合は、inputの下のpタグにエラーメッセージを表示させる。
FirebaseAuthが保持しているエラーメッセージはこちらから確認できる。

pages/register.vue
<template>
  <div>
    <div class="mt-12 px-4 py-40 bg-gray-100 md:mt-20">
      <div class="container mx-auto py-8 bg-white md:w-160">
        <h2 class="text-center text-2xl font-bold">アカウント登録</h2>
        <form @submit.prevent class="px-20 md:px-40">
          <div>
            <div class="mt-12 w-full">
              <input
                type="email"
                name="email"
                required="required"
                placeholder="メールアドレス"
                v-model="email"
                class="pl-4 w-full h-14 text-base border-2 border-solid border-black border-opacity-25 hover:border-opacity-50 rounded-md transition duration-300"
                autofocus
              />
              <p class="text-red-400">{{ emailErrorMassage }}</p>
            </div>
            <div class="mt-12 w-full">
              <input
                type="password"
                name="password"
                required="required"
                placeholder="パスワード"
                v-model="password"
                class="pl-4 w-full h-14 text-base border-2 border-solid border-black border-opacity-25 hover:border-opacity-50 rounded-md transition duration-300"
              />
              <p class="text-red-400">
                {{ passwordErrorMassage }}
              </p>
            </div>
            <button
              type="submit"
              @click="register"
              class="block mt-8 mx-auto w-2/3 h-12 text-white text-xl bg-gray-200 hover:bg-red-500 rounded-md cursor-pointer transition duration-300"
            >
              送信
            </button>
          </div>
        </form>
      </div>
    </div>
  </div>
</template>
pages/register.vue
<script>
export default {
  data: function() {
    return {
      email: "",
      password: "",
      emailErrorMassage: "",
      passwordErrorMassage: ""
    };
  },
  methods: {
    register() {
      firebase.auth()
        .createUserWithEmailAndPassword(this.email, this.password)
        .then(user => {
          alert("登録が完了しました。");
          this.$store.dispatch("checkLogin");
          this.$router.push("/main");
        })
        .catch(error => {
          console.log({ code: error.code, message: error.message });
          if (error.code === "auth/invalid-email") {
            this.emailErrorMassage = "このメールアドレスは無効です。";
          } else if (error.code === "auth/email-already-in-use") {
            this.emailErrorMassage =
              "このメールアドレスは既に使用されています。";
          } else {
            alert(
              "エラーにより登録ができませんでした。恐れ入りますが再度お試しください。"
            );
          }
        });
    }
  }
};
</script>

##2. 正規表現の追記
下記の通り、register()の下に正規表現でメールアドレスとパスワードを監視する処理を記述する。inputが空欄の時は入力を求めるメッセージを追記し、どちらかのエラーメッセ時が入っている状態であれば、firebaseを呼び出さずに処理を終了させる。

pages/register.vue
<script>
export default {
  data: function() {
    return {
      email: "",
      password: "",
      emailErrorMassage: "",
      passwordErrorMassage: "",
      emailRegexp: /^[A-Za-z0-9]{1}[A-Za-z0-9_.-]*@{1}[A-Za-z0-9_.-]{1,}\.[A-Za-z0-9]{1,}$/,
      passwordRegexp: /^(?=.*?[a-z])(?=.*?\d)[a-z\d]{8,20}$/i
    };
  },
  methods: {
    register() {
      if (!this.emailRegexp.test(this.email)) {
        this.emailErrorMassage =
          "このメールアドレスは無効です。正しい形式で入力してください。";
      }
      if (!this.passwordRegexp.test(this.password)) {
        this.passwordErrorMassage =
          "このパスワードは無効です。半角英数字を含んで8-20文字の範囲内で入力してください。";
      }
      if (this.email === "") {
        this.emailErrorMassage = "メールアドレスを入力してください。";
      }
      if (this.password === "") {
        this.passwordErrorMassage = "パスワードを入力してください。";
      }
      if (this.emailErrorMassage !== "" || this.passwordErrorMassage !== "") {
        return;
      }
      firebase.auth()
        .createUserWithEmailAndPassword(this.email, this.password)
        .then(user => {
          alert("登録が完了しました。");
          this.$store.dispatch("checkLogin");
          this.$router.push("/main");
        })
        .catch(error => {
          console.log({ code: error.code, message: error.message });
          if (error.code === "auth/invalid-email") {
            this.emailErrorMassage = "このメールアドレスは無効です。";
          } else if (error.code === "auth/email-already-in-use") {
            this.emailErrorMassage =
              "このメールアドレスは既に使用されています。";
          } else {
            alert(
              "エラーにより登録ができませんでした。恐れ入りますが再度お試しください。"
            );
          }
        });
    }
  }
};
</script>

##3. 入力中はエラーメッセージを非表示にする
このままの実装でも問題はないが、エラーメッセージが表示された後に修正しようとすると、入力中も表示されたままの状態になってしまう。
ユーザを考慮すると、修正している最中もエラーメッセージが表示されていてはストレスをかけてしまうので、修正中は非表示にする処理を記述します。

pages/register.vue
<template>
  <div>
    <div class="mt-12 px-4 py-40 bg-gray-100 md:mt-20">
      <div class="container mx-auto py-8 bg-white md:w-160">
        <h2 class="text-center text-2xl font-bold">アカウント登録</h2>
        <form @submit.prevent class="px-20 md:px-40">
          <div>
            <div class="mt-12 w-full">
              <input
                type="email"
                name="email"
                required="required"
                placeholder="メールアドレス"
                v-model="email"
                @input="isInput"
                class="pl-4 w-full h-14 text-base border-2 border-solid border-black border-opacity-25 hover:border-opacity-50 rounded-md transition duration-300"
                autofocus
              />
              <p class="text-red-400">{{ emailErrorMassage }}</p>
            </div>
            <div class="mt-12 w-full">
              <input
                type="password"
                name="password"
                required="required"
                placeholder="パスワード"
                v-model="password"
                @input="isInput"
                class="pl-4 w-full h-14 text-base border-2 border-solid border-black border-opacity-25 hover:border-opacity-50 rounded-md transition duration-300"
              />
              <p class="text-red-400">
                {{ passwordErrorMassage }}
              </p>
            </div>
            <button
              type="submit"
              @click="register"
              class="block mt-8 mx-auto w-2/3 h-12 text-white text-xl bg-gray-200 hover:bg-red-500 rounded-md cursor-pointer transition duration-300"
            >
              送信
            </button>
          </div>
        </form>
      </div>
    </div>
  </div>
</template>
pages/register.vue
<script>
export default {
  data: function() {
    return {
      email: "",
      password: "",
      emailErrorMassage: "",
      passwordErrorMassage: "",
      emailRegexp: /^[A-Za-z0-9]{1}[A-Za-z0-9_.-]*@{1}[A-Za-z0-9_.-]{1,}\.[A-Za-z0-9]{1,}$/,
      passwordRegexp: /^(?=.*?[a-z])(?=.*?\d)[a-z\d]{8,20}$/i
    };
  },
  methods: {
    register() {
      if (!this.emailRegexp.test(this.email)) {
        this.emailErrorMassage =
          "このメールアドレスは無効です。正しい形式で入力してください。";
      }
      if (!this.passwordRegexp.test(this.password)) {
        this.passwordErrorMassage =
          "このパスワードは無効です。半角英数字を含んで8-20文字の範囲内で入力してください。";
      }
      if (this.email === "") {
        this.emailErrorMassage = "メールアドレスを入力してください。";
      }
      if (this.password === "") {
        this.passwordErrorMassage = "パスワードを入力してください。";
      }
      if (this.emailErrorMassage !== "" || this.passwordErrorMassage !== "") {
        return;
      }
      firebase.auth()
        .createUserWithEmailAndPassword(this.email, this.password)
        .then(user => {
          alert("登録が完了しました。");
          this.$store.dispatch("checkLogin");
          this.$router.push("/main");
        })
        .catch(error => {
          console.log({ code: error.code, message: error.message });
          if (error.code === "auth/invalid-email") {
            this.emailErrorMassage = "このメールアドレスは無効です。";
          } else if (error.code === "auth/email-already-in-use") {
            this.emailErrorMassage =
              "このメールアドレスは既に使用されています。";
          } else {
            alert(
              "エラーにより登録ができませんでした。恐れ入りますが再度お試しください。"
            );
          }
        });
    },
    isInput() {
      this.emailErrorMassage = "";
      this.passwordErrorMassage = "";
    }
  }
};
</script>

メールアドレスとパスワードのinputタグに@input="isInput"を追記し、入力を始めるとmethods.isInputが発火して、エラーメッセージを表示しないようにすることができます。

参考記事:https://qiita.com/kj455/items/8e6b5fe3755cab7ef73e#%E3%82%B3%E3%83%BC%E3%83%89


#おわりに
ここまでFirebase Authで正規表現を用いたバリデーションを行う方法についてまとめました。
ユーザに使ってもらうサービスなら当たり前かもしれませんが、安全性と操作性は常に考慮するべきことだと思うので、細かいところまで気を配れるように丁寧に進めていきます!
以上、最後まで読んでいただきありがとうございました!
よければLGTMを押してくれると嬉しいです!

1
1
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
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?