こんにちは、急に寒くなって驚きを隠し切れない奥田です。
前回はLaravel5開発環境の構築について書きました。Homesteadを使ってLaravel5開発環境を構築する
なので今回はLaravelの標準機能として備わっている認証機能を実際に触ってみて体系的にLaravel5.1の動きを見ていきたいと思います。
Table of contents
DBマイグレーションとコンフィグレーション
Laravelにはartisan(アルチザン)というCLIが用意されていて、データーベーステーブルの作成や、モデル・コントローラーの作成がコマンドラインから行えます。
CakePHPでいうBakeみたいな感じですね。
まず、前回作成したhomesteadにssh接続し、プロジェクトディレクトリに移動します。
$ homestead ssh $ cd ~/Code/laravel
そして以下のコマンドを実行するとartisanがLaravelにはじめから入っているmigrationファイルを実行し、ユーザー認証用のテーブルが作成されます。
ちなみにこれらのファイルはdatabase/migrationsディレクトリに存在しています。
$ php artisan migrate Migration table created successfully. Migrated: 2014_10_12_000000_create_users_table Migrated: 2014_10_12_100000_create_password_resets_table
データベースについてはHomesteadの場合、自動的にhomesteadというデータベースが作成されているのですが、本番環境などではデータベースを用意し、指定しなければなりません。
そういう場合本番環境と開発環境で別の設定になります。
それら設定は.envというファイルに記述されているので、このファイルをそれぞれ用意しておけば良いようです。
DB_HOST=localhost DB_DATABASE=homestead DB_USERNAME=homestead DB_PASSWORD=secret
その下にメールの設定を記述する箇所があるのでパスワード再発行用のメールを送信する必要があるためここを書き換えておきます。
今回はGmailを利用してみようと思います。※お持ちのメールアカウントに書き換えてください。
MAIL_DRIVER=smtp MAIL_HOST=smtp.gmail.com MAIL_PORT=587 MAIL_USERNAME=メールアドレス MAIL_PASSWORD=パスワード MAIL_ENCRYPTION=tls MAIL_FROM_ADDRESS=FROMアドレス
さらに、メール送信時にfromアドレスがないとエラーが出るのでconfig/mail.phpを編集します。
// 'from' => ['address' => null, 'name' => null], ※コメントアウト // Global "From" Address 'from' => [ 'address' => env('MAIL_FROM_ADDRESS', null), 'name' => env('MAIL_FROM_NAME', null) ],
次に、Laravel5からFORMとHTMLを生成するヘルパークラスが分離されたそうなので使えるようにインストールします。(公式ドキュメントではヘルパーを使わずに記述されています。)
$ composer require "illuminate/html:5.0.*"
次にこれらを使えるようにconfig/app.phpを編集します。
'providers' => [ ・・・ Illuminate\Html\HtmlServiceProvider::class,//追記 ・・・ 'aliases' => [ ・・・ 'Form' => Illuminate\Html\FormFacade::class,//追記 'HTML' => Illuminate\Html\HtmlFacade::class,//追記 ],
これで設定は完了です。
ルーティングの設定とテンプレートの作成
多くのフレームワークで肝となるのがルーティングでしょう。
Laravelの場合はapp/routes.phpに記述していきます。
はじめは以下のように書かれています。
Route::get('/', function () { return view('welcome'); });
これは’/’にアクセスされた際、welcomeというビューを表示するという設定です。
welcomeビューはresources/views/welcome.blade.phpのことを指しています。そう、Laravelの初期画面です。
第二引数は関数で指定していますが、文字列や配列で指定することもできます。文字列で指定する場合はコントローラー名@メソッド名(アクション名)という形にします。
今回は公式ドキュメント通りのルーティングで、すでに用意されているコントローラーとメソッドを指定します。
/* ログイン画面の表示 */ Route::get('auth/login', 'Auth\AuthController@getLogin'); /* ログイン処理 */ Route::post('auth/login', 'Auth\AuthController@postLogin'); /* ログアウト */ Route::get('auth/logout', 'Auth\AuthController@getLogout'); /* ユーザー登録画面の表示 */ Route::get('auth/register', 'Auth\AuthController@getRegister'); /* ユーザー登録処理 */ Route::post('auth/register', 'Auth\AuthController@postRegister');
次に管理画面用のテンプレートビューを作成します。今回はBootstrap3を使用します。
resources/views/auth.blade.phpを作成し、以下のように記述します。
LaravelはBladeというテンプレートエンジンを採用しています。詳しくはこちらをご覧ください。
{{-- resources/views/auth.blade.php --}} <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>Laravel Login Demo</title> <meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no" /> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"> <!--[if lt IE 9]> <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script> <script src="//oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script> <![endif]--> </head> <body> <div id="page"> @include('auth.header') <div id="contents"> @yield('content') </div><!-- / #contents --> </div><!-- #page --> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script> </body> </html>
Header部分を別のビューに切り分けます。
Auth::guest()とAuth::check()でログインしているかいないかをBooleanで返してくれます。
{{-- resources/views/auth/header.blade.php --}} <header id="header"> <nav class="navbar navbar-default"> <div class="container"> <a class="navbar-brand" id="logo" href=""> Laravel Demo </a> <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> <ul class="nav navbar-nav navbar-right hidden-sm"> @if(Auth::check()) <li><a href="{{ url('home') }}">ダッシュボード</a></li> @endif @if(Auth::guest()) <li><a href="{{ url('auth/login') }}">ログイン</a></li> @endif @if(Auth::guest()) <li><a href="{{ url('auth/register') }}">サインアップ</a></li> @endif @if(Auth::check()) <li><a href="{{ url('auth/logout') }}">ログアウト</a></li> @endif </ul> </div> </div> </nav> </header><!-- #header -->
これでテンプレートの準備は完了です。
ビューの作成
では各ページのビューを作っていきます。
ログインページ
{{-- resources/views/auth/login.blade.php --}} @extends('auth') @section('content') <div class="page-header"> <div class="container"> <h2>Login</h2> </div> </div> <div class="container"> <div class="row"> <div class="col-md-6 col-md-offset-3"> <div class="panel-body"> @if (count($errors) > 0) <div class="alert alert-danger"> <strong>Error!</strong> ログインできませんでした。 </div> @endif <div class="form-horizontal"> {!! Form::open() !!} <div class="form-group"> {!! Form::label('email', 'メールアドレス', array('class' => 'col-md-3 text-right')) !!} <div class="col-md-9"> {!! Form::input('email','email','', array('class' => 'form-control')) !!} </div> </div> <div class="form-group"> {!! Form::label('password', 'パスワード', array('class' => 'col-md-3 text-right')) !!} <div class="col-md-9"> {!! Form::input('password','password','', array('class' => 'form-control')) !!} </div> </div> <div class="form-group"> <div class="col-md-offset-3 col-md-9"> {!! Form::input('checkbox','remember',null,array('id'=>'remember')) !!} {!! Form::label('remember', 'パスワードを記憶する') !!} </div> </div> <div class="form-group"> <div class="col-md-offset-3 col-md-9"> {!! Form::submit('ログイン', array('class' => 'btn btn-primary')) !!}<br><br> <a href="{{ url('password/email') }}">パスワードを再発行する</a> </div> </div> {!! Form::close() !!} </div> </div> </div> </div> </div> @endsection
ユーザー登録ページ
{{-- resources/views/auth/register.blade.php --}} @extends('auth') @section('content') <div class="page-header"> <div class="container"> <h2>Sign up</h2> </div> </div> <div class="container"> <div class="row"> <div class="col-md-6 col-md-offset-3"> <div class="panel-body"> @if (count($errors) > 0) <div class="alert alert-danger"> <strong>Error!</strong> 登録できませんでした。 <ul> @foreach ($errors->all() as $error) <li>{{ $error }}</li> @endforeach </ul> </div> @endif <div class="form-horizontal"> {!! Form::open() !!} <div class="form-group"> {!! Form::label('name', 'ユーザー名', array('class' => 'col-md-4 text-right')) !!} <div class="col-md-8"> {!! Form::input('text','name','', array('class' => 'form-control')) !!} </div> </div> <div class="form-group"> {!! Form::label('email', 'メールアドレス', array('class' => 'col-md-4 text-right')) !!} <div class="col-md-8"> {!! Form::input('email','email','', array('class' => 'form-control')) !!} </div> </div> <div class="form-group"> {!! Form::label('password', 'パスワード', array('class' => 'col-md-4 text-right')) !!} <div class="col-md-8"> {!! Form::input('password','password','', array('class' => 'form-control')) !!} </div> </div> <div class="form-group"> {!! Form::label('password_confirmation', 'パスワードの確認', array('class' => 'col-md-4 text-right')) !!} <div class="col-md-8"> {!! Form::input('password','password_confirmation','', array('class' => 'form-control')) !!} </div> </div> <div class="form-group"> <div class="col-md-offset-4 col-md-8"> {!! Form::submit('サインアップ', array('class' => 'btn btn-primary')) !!} </div> </div> {!! Form::close() !!} </div> </div> </div> </div> </div> @endsection
これで homestead.app/auth/register/ にアクセスするとユーザー登録画面が表示されると思います。
ログイン後の画面の作成
ただ、このままだとログイン後のページに遷移した際、エラー画面となってしまいます。
LaravelのAuthではログイン後/homeにリダイレクトする設定になっているのでそのまま/homeのルーティングを作成します。
routes.phpに以下を追記します。
/* 管理画面 */ Route::get('/home', ['middleware' => 'auth', 'uses' => 'DashboardController@index']);
‘middleware’=>’auth’とは認証が必要なページに認証済みかのチェックを行うということです。
非認証だとこのページにアクセスできません。usesはどのコントローラーを使用するかを指定できます。
上記に書いたようにDashboardContoroller.phpのindexアクションを作成します。
artisanのmake:controllerコマンドでcontrollerを作成できます。
$ php artisan make:controller DashboardController Controller created successfully.
app/Http/ControllersにDashboardContoroller.phpが作成されているのでそれを開き、indexメソッド内に以下を追記しビューを指定します。
class DashboardController extends Controller { /** * Display a listing of the resource. * * @return \Illuminate\Http\Response */ public function index() { return view('auth.index'); }
resources/views/auth/index.blade.phpを作成します。
{{-- resources/views/auth/index.blade.php --}} @extends('auth') @section('content') <div class="page-header"> <div class="container"> <h2>Dashboard</h2> </div> </div> <?php $user = Auth::user() ?> <div class="container"> こんにちは {{ $user['name'] }} さん </div> </div> @endsection
ログインユーザーの情報はAuth::user()で取得できます。
ではユーザー登録 → ログイン → ダッシュボードの手順を踏んでみます。
以下のように表示されれば成功です。
パスワード再設定画面の作成
最後にパスワード再設定用のビューを作成します。これもAuthは用意してくれています。
ルーティングは以下のようにしてください。
// パスワードリセットリンクを要求するルート… Route::get('password/email', 'Auth\PasswordController@getEmail'); Route::post('password/email', 'Auth\PasswordController@postEmail'); // パスワードリセットルート Route::get('password/reset/{token}', 'Auth\PasswordController@getReset'); Route::post('password/reset', 'Auth\PasswordController@postReset');
流れはよくあるTokenを使ったものです。
メールアドレスを入力し、Tokenが付いたURLが入力したメールアドレスに送られてきます。
そこにアクセスし、パスワードを入力すればリセットの完了です。
では、ビューを作成していきます。
メールアドレス入力画面
{{-- resources/views/auth/password.blade.php --}} @extends('auth') @section('content') <div class="page-header"> <div class="container"> <h2>Password Reset</h2> </div> </div> <div class="container"> <div class="row"> <div class="col-md-6 col-md-offset-3"> <div class="panel-body"> @if (count($errors) > 0) <div class="alert alert-danger"> <strong>Error!</strong> <ul> @foreach ($errors->all() as $error) <li>{{ $error }}</li> @endforeach </ul> </div> @endif <div class="form-horizontal"> {!! Form::open() !!} <div class="form-group"> {!! Form::label('email', 'メールアドレス', array('class' => 'col-md-3 text-right')) !!} <div class="col-md-9"> {!! Form::input('email','email','', array('class' => 'form-control')) !!} </div> </div> <div class="form-group"> <div class="col-md-offset-3 col-md-9"> {!! Form::submit('パスワードを再発行する', array('class' => 'btn btn-success')) !!} </div> </div> {!! Form::close() !!} </div> </div> </div> </div> </div> @endsection
パスワード再設定画面
{{-- resources/views/auth/reset.blade.php --}} @extends('auth') @section('content') <div class="page-header"> <div class="container"> <h2>Password Reset</h2> </div> </div> <div class="container"> <div class="row"> <div class="col-md-6 col-md-offset-3"> <div class="panel-body"> @if (count($errors) > 0) <div class="alert alert-danger"> <strong>Error!</strong> パスワードをリセットできませんでした。 <ul> @foreach ($errors->all() as $error) <li>{{ $error }}</li> @endforeach </ul> </div> @endif <div class="form-horizontal"> {!! Form::open(array('url' => '/password/reset/')) !!} {!! Form::input('hidden','token',$token) !!} <div class="form-group"> {!! Form::label('email', 'メールアドレス', array('class' => 'col-md-3 text-right')) !!} <div class="col-md-9"> {!! Form::input('email','email','', array('class' => 'form-control')) !!} </div> </div> <div class="form-group"> {!! Form::label('password', 'パスワード', array('class' => 'col-md-3 text-right')) !!} <div class="col-md-9"> {!! Form::input('password','password','', array('class' => 'form-control')) !!} </div> </div> <div class="form-group"> {!! Form::label('password_confirmation', 'パスワード確認', array('class' => 'col-md-3 text-right')) !!} <div class="col-md-9"> {!! Form::input('password','password_confirmation','', array('class' => 'form-control')) !!} </div> </div> <div class="form-group"> <div class="col-md-offset-3 col-md-9"> {!! Form::submit('パスワードリセット', array('class' => 'btn btn-success')) !!} </div> </div> {!! Form::close() !!} </div> </div> </div> </div> </div> @endsection
メールのテンプレートが必要なので作成します。
resources/emails/にpassword.blade.phpを作成します。
メールテンプレート
{{-- resources/emails/password.blade.php --}} パスワードをリセットするためにリンクをクリックしてください。 {{ url('password/reset/'.$token) }}
これで認証の一通りの流れはできたのではないでしょうか?
Laravelはロジックをほぼ書くことなく認証機能を実装することができてしまいます。
さらに、ソーシャル認証なども用意されています。
artisanの書き方に慣れるためにもぜひお試しください。