tohokuaikiのチラシの裏

技術的ネタとか。

Laravel リファレンス 4-1 認証

さて、だいたい慣れてきた。折角なのでここからは与えられたサンプルコードを使わずに一から作っていこうと思う。
もちろんサンプルコードは参考にする。

とりあえず、プロジェクトの開始

すっかり忘れてしまったのだけど、.bashrcに

export COMPOSER_HOME=~/.composer
export PATH=$PATH:~/bin:$COMPOSER_HOME/vendor/bin

と書き、~/.composer/composer.json

{
    "require": {
        "laravel/installer": "~1.1"
    }
}

としているので、~/.composerにて $composer updateする。もちろん、~/bin/にcomposer.pharを入れている。すると、Laravel Installerによるlaravelコマンドが任意の場所で使える。

プロジェクトの作成

$ laravel new ~/laravel/auth_sample

でとりあえず、雛形作成。キー生成も済んでいる。

データベースの作成

作るテーブルの情報はP.158の表4.2と表4.3の通り。

マイグレーションの作成

usersテーブルを作るMigration

$ ./artisan make:migration create_user_table --create=users
Created Migration: 2016_12_29_124332_create_user_table

password_resetsテーブルを作るMigration

$ ./artisan make:migration create_password_resets_table --create=password_resets


  [InvalidArgumentException]
  A CreatePasswordResetsTable migration already exists.

???あれ、既にある。

$ ls database/migrations/
2014_10_12_000000_create_users_table.php  2014_10_12_100000_create_password_resets_table.php  2016_12_29_124332_create_user_table.php
$ ./artisan make:migration create_users_table --create=users


  [InvalidArgumentException]
  A CreateUsersTable migration already exists.

あるじゃん・・・というか、usersテーブルもあるんだ。

ということで、さっき作った2016_12_29_124332_create_user_table.phpを削除して、composer dump-autoloadする。

マイグレーションの実行

$ ./artisan migrate
Migration table created successfully.
Migrated: 2014_10_12_000000_create_users_table
Migrated: 2014_10_12_100000_create_password_resets_table
$ mysql -u **** -p**** laravel_authsample -e "show tables"
+------------------------------+
| Tables_in_laravel_authsample |
+------------------------------+
| migrations                   |
| password_resets              |
| users                        |
+------------------------------+

作成完了。

Modelクラスを作る

$ ./artisan make:model User
Model already exists!

・・・あれ、もうできてる。

認証機能の設定

コントローラの配置

書籍によると、

  • app/Http/Controllers/Auth/AuthController.php
  • app/Http/Controllers/Auth/PasswordController.php

の2つが既にあるらしい。

5.3だとそれらは無いのだが、

  • app/Http/Controllers/Auth/RegisterController.php
  • app/Http/Controllers/Auth/ResetPasswordController.php

の2つがある。見た感じそれぞれが対応しそうである。

認証の設定

config/auth.php が本の5.1とは随分と異なっている。

肝心な部分はここだと思われる。

<?php
    'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model' => App\User::class,
        ],

        // 'users' => [
        //     'driver' => 'database',
        //     'table' => 'users',
        // ],
    ],

このままでおそらく本書と同じであろうからそのまま。

メッセージファイル

resources/lang/ja/passwords.php を作成。面倒なので、本書のサンプルコードをそのままコピー。

ルーティング

Routingを行う。

routes/web.php

<?php
Route::resource('/register', 'Auth\RegisterController');

を追加。

実装開始

とりあえず・・・

雛形のAuth\RegisterControllerは、Illuminate/Foundation/Auth/RegistersUsers をtraitしているのでこのクラスを使ってみる。

GET/indexを追加

<?php
    protected function index() {
        return $this->showRegistrationForm();
    }

いきなりLaravel5.1と5.3での違いに戸惑う

で、次はpost周りを・・・と思ったけど Illuminate/Foundation/Auth/RegistersUsers.phpが5.1と5.3では大きく変わってる。

あれー、と思って調べるとHow to register a user in Laravel 5.3?で「Route::auth()」使うんやでっていうコメントが。

Illuminate/Routing/Router.php のauth()を見てみると、あー。。。なんか色々とRoutingしてくれている。

ということで、 routes/web.php

<?php
// Route::resource('/register', 'Auth\RegisterController');
Route::auth();

と変更。Auth\RegisterControllerに付け加えた protected function index()も削除。

findすると vendor/laravel/framework/src/Illuminate/Auth/Console/stubs/make/views/auth/register.stub なるスタブもある。

んんん~~。と思い、調べると、artisanにmake:authコマンドがある。

結局、make:authコマンドの実行がベスト

./resources/views/layouts/app.blade.php
./resources/views/auth/register.blade.php
./resources/views/auth/passwords/reset.blade.php
./resources/views/auth/passwords/email.blade.php
./resources/views/auth/login.blade.php
./resources/views/home.blade.php
./app/Http/Controllers/HomeController.php

が追加されていた。

routes/web.phpには以下の2行が追記されていた。もはや、Route::auth()メソッドですらない。

<?php
Auth::routes();

Route::get('/home', 'HomeController@index');

Authの機能について

Authファサードでよく使いそうな機能について

Auth::attempt()

普通のHTTPの場合なので、実態は、Illuminate/Auth/SessionGuard.php

  • 第1引数:usersテーブルに合致する情報の配列。ただし、passwordをキーに持つ値の場合はhasherによりHash化される。
  • 第2引数:trueにすると自動ログ引用トークンを発行。そのトークンを持っているだけでログインできる。
  • 第3引数:trueにすると認証が正当な場合にログイン処理を行う。

実際には、Illuminate/Foundation/Auth/AuthenticatesUsers.php のlogin()にて使われている。 これを直接使うのはあまり無いかも知れない。

Auth::check()

ログイン状態のチェックをする。guest()メソッドはこれの反転。Bladeテンプレートでも @if (Auth::guest()) とかで簡単に使える。

Auth::viaRemember()

Tokenによるログインを行ったかどうか。

セッションが切れてCookieのRememberトークンによるログインになった場合はこれがtrueになる。

Auth::user()

App\Userオブジェクトを返してくれる。

Controllerメソッド(あるいはRoutingの際のClosure)のTypeHinting

これ、どうやって実装してるんだろう・・・・。

Middlewareではなく、config/auth.phpで設定される何かから引っ張ってきているんだろうとは思うんだけど。

何となくこんな感じというのを調べてみた。 LaravelのメソッドのTypeHintがどうやってパラメータをうまい具合にセットしているのか? - tohokuaikiのチラシの裏

Illuminate\Http\RequestをTypeHintingに使うと、$request->user()でユーザー情報が取れる。

RoutingのClosureで使う場合

<?php
use Illuminate\Http\Request;

Route::get('/', function (Request $request) {
    dd($request->user());
    return view('welcome');
});

Controllerメソッドで使う場合。

<?php
use Illuminate\Http\Request;

class HomeController extends Controller
{
    /**
     * Show the application dashboard.
     *
     * @return \Illuminate\Http\Response
     */
    public function index(Request $request)
    {
        dd($request->user());
        return view('home');
    }
Illuminate\Contracts\Auth\Authenticatable をTypeHintingに使うとApp\Userオブジェクトがそのまま入ってくる。

ただし、この場合は認証を通過していないと引数にnullが入ってしまい

Controller::index() must implement interface Illuminate\Contracts\Auth\Authenticatable, none given

のエラーが出てしまう。

従って、

<?php
    public function __construct()
    {
        $this->middleware('auth');
    }

として、middlewareにてAuthチェックを行うなどする必要がある。

Auth::login() / Auth::loginUsingId()

どちらも任意のログインユーザーでログインする。テストを書く時に使う。

<?php
Auth::login(new \App\User::find(1));

Auth::loginUsingId(1);

Auth::once()

1リクエスト内で有効なログイン状態を作る。それ以外はAuth::attempt()と同じ。