Laravelの認証MiddleWareを作ってみる

スケルトンに存在してるのですが、各Controllerにアクセスされた際に、MiddleWareを通すことで

- 会員ページで、ログインされていたらそのまま、されていなかったらログイン画面へ
- ログイン画面でログインされれていたら

を振り分けを作ります。

機能的にはフルには使ってないですが、その分Middlewareについてと認証については多少わかりすく感じる人もいるんじゃないかなということで残します。
デフォルトSkeltonでメールでの認証等を含めた高機能なものがすでに準備されているが、
今回作ろうとした社内システムでそんなのは高機能すぎるので、認証したりセッションで保持する部分だけは利用して、そのほかを簡素化しました。

- Laravel5.6
- PHP7.2
- MySQL
- Windows10 XAMPP(これを基に実装したものはCentOS7等でも確認済)

ソースは
https://github.com/miyawa-tarou/laravel_auth

### MiddleWareを作って使えるように登録する

```
$ composer create-project laravel/laravel auth_project --prefer-dist
$ cd auth_project
$ php artisan  make:middleware Authenticate
```

./app/Http/Middleware 以下に作られます
これだけだとまだ読み込めないので、読み込めるように追加します

```php:app/Http/Kernel.php
    protected $routeMiddleware = [
        'auth' => \App\Http\Middleware\Auth::class,

...

    ]

```
これで$this->middleware('auth')で呼び出せるようになります。

### 呼び出された時の処理を入れる

./app/Http/Middleware/Authenticate::handle()　を触ります

```php:app/Http/Middleware/Authenticate.php
use Illuminate\Support\Facades\Auth;
class Authenticate
{
    public function handle($request, Closure $next)
    {
        if (!Auth::check()) { // 非ログインはログインページに飛ばす
            return redirect('/login');
        }
        return $next($request);
    }
}
```

最終的には正常なら return $next($request); をします。今回はその前に未ログインならリダイレクトという処理を追加しました。
Auth::check()　でチェックできます。

この辺はLaravelの認証の説明に詳しく載っています
https://readouble.com/laravel/5.6/ja/authentication.html

### ページを追加する

```
$ php artisan make:controller IndexController
$ php artisan make:controller LoginController
```

```php:routes/web.php
Route::get('/', 'IndexController@index');
Route::get('/login', 'LoginController@index');
```

viewはテキトーにつくります。
https://github.com/miyawa-tarou/laravel_auth/compare/01_add_auth...02_add_controller

### indexにログイン制限を入れる

先ほどのMiddlewareが適用されるようにします。
Controller全体に適用するため、__construct()で呼び出します。

```php:IndexController
class IndexController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth');
    }
    

...
}
```
これで / に飛ぶとなんのログインセッションも持っていないため、/loginに転送されます


### 認証用ユーザーテーブルを作る

```
$ php artisan make:migration make_auth_user
```

```php:database/migrations/2018_06_XX_XXXXXX_make_auth_user.php
class MakeAuthUser extends Migration
{
    public function up()
    {
        Schema::create('auth_user', function (Blueprint $table) {
            $table->increments('id');
            $table->string('nm');
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
        });
    }

    public function down()
    {
        Schema::dropIfExists('auth_user');
    }
}
```
nameはあえてnmに変えてみましたが、
passwordはpasswordである必要があるらしく、また中身は\Illuminate\Support\Facades\Hash::make() で作った値である必要があるようです
漏れましたが、多分nmはuniqueであるべきですね（指定しなくても動くことは動きますが、重複するとダメそうです）。
またrememberTokenは、必須なようです。

##### モデルを作る

```
$ php artisan make:model AuthUser
```

```php:AuthUser.php
use Illuminate\Foundation\Auth\User as Authenticatable;

class AuthUser extends Authenticatable
{
    protected $table = 'auth_user';
}
```
通常のモデルではなく、Illuminate\Foundation\Auth\Userを用います

##### モデルをauth用に設定する

```php:config/auth.php
    'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model' => App\AuthUser::class, // ここがデフォルトUsersなので変更する。
        ],
    ],
```

とりあえずさぼってnm=test,passowrd=test_passのユーザーをmigrationで追加しています。

### ログインを作ってみる

もろもろHTML周りは省略します。
postでname,passwordとして送信されるようにして、

```php
        if (Auth::attempt(['nm' => $request->post('name'), 'password' => $request->post('password')])) {
            return redirect('/');
        }
```

Auth::attempt() で認証します。認証方法はほかにもあるようです。

### ログイン済だとログインページに飛べないようにする

ログイン済でログインページに飛んだらトップページに転送されるようにする
ログイン済み用Middleware"guest"を作成し

```php
$this->middleware('guest');
```

```php:app/Http/Middleware/Guest.php
use Illuminate\Support\Facades\Auth;
class Guest
{
    public function handle($request, Closure $next)
    {
        if (Auth::check()) { // ログイン済みならトップに飛ばす
            return redirect('/');
        }
        return $next($request);
    }
}
```

actionで適用するMiddlewareを分ける

```php
        $this->middleware('guest')->except('logout', 'user', 'userReg');
//      $this->middleware('guest')->only('login');
        $this->middleware('auth')->only('logout', 'user', 'userReg');
```

完成
https://github.com/miyawa-tarou/laravel_auth

実際には登録処理とかいると思うので、そのあたりはよしなに。


### 資料

- https://readouble.com/laravel/5.6/ja/authentication.html
- https://qiita.com/zaburo/items/9fcf0f4c771e011a4d35