20190503のlaravelに関する記事は2件です。

モダンな技術を全く知らないSIer5年目題Webサービスを作ることになったため0から勉強する〜Nuxt +メール認証+パスワードリセット〜

はじめに

現在SIer5年目でjavascript(Jqueryのみ)、PHP(フレームワーク無し)を2年ほど、C#(Windowsアプリ)3年ほどやってきました。
色々なご縁があり、個人で最近Webサービスの立ち上げをやることになったのですが何せ本当にWebサービスを立ち上げるための知識がほぼ0に等しいです:sob:

ただ今後のキャリアを考えた時に今のままではいけないと思いチャレンジすることにしました。

まずは最初に技術を習得しないといけないので、学ぶ&アウトプットするために毎回投稿していこうと思います。
今後身についていこうと思ってるのは下記のような技術です。
AWS
Docker
CI/CD環境の構築
Laravel
Nuxt.js
今回はLaravel+Nuxtについて学んでいきます。

今回学ぶこと

Laravel+Nuxtでのメール認証機能とパスワードリセット機能を作成していこうかと思います。
今回はLaravel API側の実装をしていきます

参考サイト

jwt-auth公式サイト

こちらのサイトを参考にさせていただきました

メール認証の概要は個々がわかりやっすかったです。

前提

Laravel 5.8
Nuxt 2.5.4
jwt-auth

メール認証とパスワードリセットのAPI側実装はこちらで実装してるのでこちらを参照ください

最終的なソースコードはこちらになります。
※今回は、Nuxt側の実装でLaravel側も変更している箇所もあるのでそちらもソースコード確認してもらえたらと思います。

Nuxt側のvueファイルを作成する

フロント側はメール認証+パスワード再発行を実現するための画面とミドルウェアを作成します。

vue_file 概要
client/pages/auth/resetpassword.vue パスワードを変更する画面、パスワード変更時にトークンも一緒に送る
client/pages/auth/resendverify.vue メール認証のリンクを送るための画面
client/pages/auth/forgotpassword.vue メールアドレスを入力し、パスワード再発行メールを送信する画面
client/pages/auth/emailverification.vue メール認証中の際に表示する画面
client/middleware/emailVerify.js メール認証済みかチェックを行うミドルウェア

パスワードリセットを実装する

まずはパスワードリセットを実装するにあたっての処理の流れはこんな感じになります。

  1. ログイン画面からForgot Your Passwordリンクをクリックし、パスワード再発行のメールアドレスを入力するforgotpassword.vueを表示する
  2. メールアドレスを入力し、再発行ボタンを押下するとlocalhost/api/auth/password/emailAPIに対してリクエストが投げられ指定したアドレスにパスワード再発行メールを送る
  3. メールのリンクをクリックするとresetpassword.vueを表示し、リセットするパスワードを入力し、リンクに乗ってるqueryURLに対してリクエストを投げる
  4. パスワードリセットが完了したら、ログイン画面に遷移する

ログイン画面からforgotpassword.vueに遷移するリンクを作成

client/pages/auth/login.vue
<div class="form-group">
  <input type="submit" value="Login" class="btn btn-default w-100">
  <nuxt-link class="nav-link" to="/auth/forgotpassword">Forgot Your Password</nuxt-link>
</div>

パスワードリセット対象のメールアドレス入力画面を実装する

client/pages/auth/forgotpassword.vue
<template>
  <div class="container">
    <div class="col-md-6 offset-md-3">
      <div class="card mt-4">
        <div class="card-header">
          <p class="mb-0">ForgotPassword</p>
        </div>
        <div class="card-body">
          <b-alert variant="success" v-model="showSuccessAlert">I have sent a password reissue email</b-alert> <!-- パスワードリセットメールを送れたことをメッセージで表示する -->
          <form @submit.prevent="ReSendVerifyEmail">
            <div class="form-group">
              <label>Email</label>
              <input v-model="form.email" type="email" class="form-control" :class="{ 'is-invalid': errors.email }" placeholder="Email">
            </div>
            <div class="form-group">
              <input type="submit" value="SendResetLinkEmail" class="btn btn-default w-100">
            </div>
          </form>
        </div>
      </div>
    </div>

  </div>
</template>

<script>
  export default {
    middleware: 'guest', //ログインであればリダイレクトする
    data() {
      return {
        form: {
          email: '',
        },
        showSuccessAlert: false

      }
    },
    methods: {
      async ReSendVerifyEmail(){
        // パスワードリセットのメール送信APIを実行する
        await this.$axios.post('/auth/password/email', this.form)
          .then(data => {
            // 送信完了メッセージ表示
            this.showSuccessAlert = true;

          })
          .catch(err=> {

            console.log(err);
          });


      }
    }

  }
</script>

リセットするパスワード入力する画面

client/pages/auth/resetpassword.vue
<template>
  <div class="container">
    <div class="col-md-6 offset-md-3">
      <div class="card mt-4">
        <div class="card-header">
          <p class="mb-0">Register</p>
        </div>
        <div class="card-body">
          <form @submit.prevent="ResetPassword"> <!-- 標準のsubmitは実行しない -->
            <div class="form-group">
              <label>Email</label>
              <input v-model="form.email" type="email" class="form-control" :class="{ 'is-invalid': errors.email }" placeholder="Email">
              <div class="invalid-feedback" v-if="errors.email">
                {{ errors.email[0] }}
              </div>
            </div>
            <div class="form-group">
              <label>Password</label>
              <input v-model="form.password" type="password" class="form-control" :class="{ 'is-invalid': errors.password }" placeholder="Password">
              <div class="invalid-feedback" v-if="errors.password">
                {{ errors.password[0] }}
              </div>
            </div>
            <div class="form-group">
              <label>Password Confirmation</label>
              <input v-model="form.password_confirmation" type="password" class="form-control" :class="{ 'is-invalid': errors.password }" placeholder="Password">
              <div class="invalid-feedback" v-if="errors.password">
                {{ errors.password[0] }}
              </div>
            </div>
            <div class="form-group">
              <input type="submit" value="Register" class="btn btn-default w-100">
            </div>
          </form>
        </div>
      </div>
    </div>

  </div>
</template>

<script>
  export default {
    middleware: 'guest', //ログイン状態であればリダイレクトする
    data() {
      return {
        form: {
          email: '',                  // リセット対象のメールアドレス
          password: '',               // 新しいパスワード
          password_confirmation: '',  // 新しいパスワード確認
          token: ''                   // パスワードリセット実行するための一時的なトークン
        },
        requestUrl: ''
      }
    },

    created() {
      this.setQuery()
    },

    methods: {
      async ResetPassword(){ // パスワードリセットリクエストを投げる関数
        await this.$axios.$post(this.requestUrl, this.form)
          .then(data => {
            this.$router.push('/auth/login');
          })
          .catch(err=> {
            console.log(err);
          });
      },
      setQuery() { // getリクエストのパラメータを取得する関数
        this.requestUrl = this.$route.query.queryURL || ''; // パスワードリセットAPIのURL
        this.form.token = this.$route.query.token || '';    // パスワードリセットするために必要なToken
      },
    }

  }
</script>

メール認証を実装する

メール認証を実装するにあたっての処理流れはこんな感じになります

  1. ユーザ登録後にメール認証するためのメールを送信する
  2. メールからメール認証画面に遷移する
  3. メール認証画面では、queryURLにそのままリクエストを投げてメール認証を行い、成功したら画面遷移を行う
client/pages/auth/emailverification.vue
<template>
  <div class="container">
    <div class="col-md-6 offset-md-3">
      <div class="card mt-4">
        <div class="card-header">
          <p class="mb-0">During Verification Your Email Address</p>
        </div>
        <div class="card-body">
          <label>Validating your email address.</label>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
  export default {
    middleware: 'auth', //未ログイン状態であればリダイレクトする
    data() {
      return {
        queryURL: ''
      }
    },

    async mounted() {
      const queryURL = this.$route.query.queryURL || '';
      if (queryURL != '') {
        await this.$axios.$get(queryURL)
          .then(data => {
            this.$auth.fetchUser();             // メール認証が完了したため、ユーザ情報を再取得する
            this.$router.push({name: 'index'});
          })
          .catch(err => {
            alert('メール認証が失敗しました。再度メール認証を行ってください。');
            this.$router.push('/auth/resendverify');
          });
      }
    },
  }
</script>

メール認証チェックを行い、メール認証が必要な画面にアクセスした場合、認証メールを再送する画面にリダイレクトする

メール認証チェックを行うミドルウェアを実装する

email_verified_atはLaravelのUserモデルにはデフォルト項目であり
メール認証された場合はここに日時が入ってるため
nullの場合は未認証と判断し、リダイレクトを行う

client/middleware/emailVerify.js
//メールアドレスが認証されていなければ、メール認証の送信画面に遷移する
export default function({ store, redirect, app }) {
  if(app.$auth.user['email_verified_at'] == null) {
    return redirect('/auth/resendverify');
  }
}

メール認証チェックを行う

ダッシュボードは未認証ユーザはアクセスできないようにする

client/pages/dashboard.vue
<template>
  <div class="container">
    <h1>Welcome to the dashboard</h1>
  </div>
</template>

<script>
  export default {
    middleware: 'auth',
    middleware: 'emailVerify' // メール認証チェックを行う
  }
</script>

認証メールの再送信画面を実装する

client/pages/auth/resendverify.vue
<template>
  <div class="container">
    <div class="col-md-6 offset-md-3">
      <div class="card mt-4">
        <div class="card-header">
          <p class="mb-0">Verify Your Email Address</p>
        </div>
        <div class="card-body">
          <b-alert variant="success" v-model="showSuccessAlert">I have sent a password reissue email</b-alert>
          <label>Email verification has not been completed yet.
            Please press the button below to complete e-mail authentication</label>
          <div>
            <b-button block variant="primary" @click="ReSendVerifyEmail">Verify Email</b-button>
          </div>
        </div>
      </div>
    </div>

  </div>
</template>

<script>
  export default {
    middleware: 'auth', //ログインしてなければリダイレクトする
    data() {
      return {
        form: {
          email: '',
        },
        showSuccessAlert: false,
      }
    },

    methods: {
      async ReSendVerifyEmail(){
        await this.$axios.post('/auth/email/resend', this.form)
          .then(data => {
            this.showSuccessAlert = true;
          })
          .catch(err=> {
            console.log(err);
          });
      },

    }

  }
</script>

まとめ

フロント側はLaravelのmake:authで作成されるViewを参考に作りました
独学なので、おそらくもっと良い実装方法はあるかと思います。。。
もしこうした方がいいとかこのサイトは参考になるよなどあれば教えてもらえると幸いです。

あと、ログイン情報を保持するなどの機能はまだ実装してないのでそちらも実装できたらと思います。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laradockによるlaravel開発環境構築

はじめに

今更ですがLaravelをLaradockを使い環境構築してみます。
(この投稿は自分用メモでもあります。)

前提

docker-composeコマンドが使える

> docker-compose --version
docker-compose version 1.23.2, build 1110ad01

gitコマンドが使える

> git --version
git version 2.21.0.windows.1

ちなみにPCはWindows10 proを使用しています。

1.作業ディレクトリの作成&Laradockのクローン

# 作業ディレクトリを作成
> mkdir dockerworkspace

# 作業ディレクトリに移動
> cd dockerworkspace

# GitからLaradockをダウンロード
> git clone https://github.com/LaraDock/laradock.git

2.「.env」ファイルの作成

# laradockディレクトリに移動
> cd laradock

# env-exampleをコピーし.envファイル作成
> cp env-example .env

3.コンテナの起動

# laradockディレクトリ上で入力
# コンテナの起動
> docker-compose up -d nginx
Recreating laradock_docker-in-docker_1 ... done
Recreating laradock_workspace_1        ... done
Recreating laradock_php-fpm_1          ... done
Recreating laradock_nginx_1            ... done

コンテナの起動を確認してみましょう。

# laradockディレクトリ上で入力
# コンテナの一覧を表示
> docker-compose ps
           Name                          Command                State                      Ports
------------------------------------------------------------------------------------------------------------------
laradock_docker-in-docker_1   dockerd-entrypoint.sh            Up         2375/tcp
laradock_mysql_1              docker-entrypoint.sh mysqld      Exit 255   0.0.0.0:3306->3306/tcp, 33060/tcp
laradock_nginx_1              /bin/bash /opt/startup.sh        Up         0.0.0.0:443->443/tcp, 0.0.0.0:80->80/tcp
laradock_php-fpm_1            docker-php-entrypoint php-fpm    Up         9000/tcp
laradock_phpmyadmin_1         /run.sh supervisord -n -j  ...   Exit 255   0.0.0.0:8080->80/tcp, 9000/tcp
laradock_redis_1              docker-entrypoint.sh redis ...   Exit 255   0.0.0.0:6379->6379/tcp
laradock_workspace_1          /sbin/my_init                    Up         0.0.0.0:2222->22/tcp

Stateがupになっていれば起動していることになります。
http://localhostにアクセスします。
nginx_404.PNG

nginxの起動を確認できました。Not Foundは後ほど対処します。

4.Laravelプロジェクトの作成

laradock_workspace_1にアクセスしLaravelアプリケーションを作成します。

# laradockディレクトリ上で入力
# workspaceコンテナにアクセス
# root@xxxxxxxx:/var/www$ というディレクトリに入る
> docker-compose exec --user=laradock workspace bash

# Laravelアプリケーションの作成
# ここではsample_appという名前で作成
root@xxxxxxxx:/var/www$ composer create-project laravel/laravel sample_app

5.nginxの設定ファイルの編集

root@xxxxxxxx:/var/www$ exit

# laradockディレクトリ上で入力
# コンテナの停止
> docker-compose stop

# laradockディレクトリ上で入力
# dockerworkspace/laradock/nginx/sitesの中のdefaul.confをdefault.conf.backup等の名前にしコピー
> cd nginx/sites
> cp default.conf default.conf.backup

# 同じディレクトリにあるlaravel.conf.exampleの中のテキストをコピーし、default.confにペースト
> cp laravel.conf.example default.conf

dockerworkspace/laradock/nginx/sites/default.confを編集します。

default.conf
# 一部抜粋
server_name laravel.test;
  # root /var/www/laravel/public;     # 変更前
    root /var/www/sample_app/public;    # 変更後
    index index.php index.html index.htm;

さらにlaradockディレクトリにある.env(はじめにコピーして作ったファイルですね)も編集します。

 .env
# 一部抜粋
### Paths #################################################

# Point to the path of your applications code on your host
# APP_CODE_PATH_HOST=../            # 変更前
APP_CODE_PATH_HOST=../sample_app    # 変更後

6.LaravelのWelcome画面を見る

> docker-compose up -d nginx

http://localhostにアクセスします。
laravel_welcome.PNG

追記

MySQLに接続

設定ファイルの編集

Laradockの初期設定ではMySQLの最新が設定されており認証でエラーが出てしまうそうです。laradock/.envを編集します。

laradock/.env
### MYSQL #################################################

# MYSQL_VERSION=latest   # 変更前
MYSQL_VERSION=5.7        # 変更後

Laravelの設定もします。sample_app/.envを編集します。

sample_app/.env
DB_CONNECTION=mysql
# DB_HOST=127.0.0.1        # 変更前
DB_HOST=mysql              # 変更後
DB_PORT=3306
# DB_DATABASE=homestead    # 変更前
# DB_USERNAME=homestead    # 変更前
DB_DATABASE=default        # 変更後
DB_USERNAME=default        # 変更後
DB_PASSWORD=secret

これでMySQLへの接続ができます。

migrateしてみる

# laradockディレクトリ上で入力
> docker-compose up -d nginx mysql
# 省略
> docker-compose exec --user=laradock workspace bash
root@xxxxxxxx:/var/www$ php artisan migrate
Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated:  2014_10_12_000000_create_users_table
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated:  2014_10_12_100000_create_password_resets_table

DBを見てみる

# laradockディレクトリ上で入力
> docker-compose exec mysql bash
root@xxxxxxxxxx:/# mysql -udefault -psecret
# 省略
mysql> use default;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql > show tables;
+-------------------+
| Tables_in_default |
+-------------------+
| migrations        |
| password_resets   |
| users             |
+-------------------+
4 rows in set (0.00 sec)

最後に

DockerはLaradockでしか触ったことがないので間違った認識、改善点等ありましたらご指摘お願いいたします。:bow_tone1:
Docker勉強しよう、、、。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む