Laravelで認証設定

今日は、PHPフレームワークLaravelで認証設定について調べてみましょう。Laravelでは、認証ドライバーにEloquentドライバーとFluentドライバーが使えるようになっていて、Eloquentドライバーがデフォルトになっています。

認証設定ファイル

1. Laravelの認証設定はconfig/auth.phpファイルに記述されています。初期設定では、下記のようになっています。

laravel/application/config/auth.php

<?php
return array(
'driver' => 'eloquent',
'username' => 'email',
'password' => 'password',
'model' => 'User',
'table' => 'users',
);

2. 認証ドライバーをFluentドライバーに変更する場合は、下記のように変更します。私は、認証ドライバーはデフォルトのEloquentORMのままで作業を進めたいと思います。

laravel/application/config/auth.php

<?php
return array(
'driver' => 'fluent',
'username' => 'username',
'password' => 'password',
'model' => 'User',
'table' => 'users',
);

Usersテーブルの作成

3. それでは、usersテーブルを作成します。とりあえず最低限必要なフィールドだけを作成します。phpMyAdminを起動したら、SQLタブをクリックして、下記のように記述してusersテーブルを作成します。

CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
 `username` varchar(100) NOT NULL,
 `email` varchar(255) NOT NULL,
`password` varchar(255) NOT NULL,
`created_at` datetime NOT NULL,
 `updated_at` datetime NOT NULL,
 PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

4.  下記のようなテーブルが作成されました。phpMyAdminは、昔のバージョンの方が使いやすかった気がします。最近のバージョンはグラフィカルすぎて逆に使いにくい気がします(動作も重いですし)。

5. userフォルダを新規作成し、ユーザー作成のためのフォームcreate.blade.phpを作成します。

laravel/application/views/user/create.blade.php 

@layout('layouts.master')
@section('navigation')
 <li>{{ HTML::link('user/index','トップページ') }}</li>
@endsection
@section('content')
<div class="row">
<div class="alert alert-info">
<h4>新規ユーザーを作成します</h4>
</div>
 {{ Form::open(URL::current(),'POST',array('class'=>'form-horizontal')) }}
 <fieldset>
 <div class="control-group {{ $errors->has('username') ? 'error' : '' }}">
 {{ Form::label('username','ユーザー名',array('class'=>'control-label')) }}
 <div class="controls">
 {{ Form::text('username',Input::old('username')) }}
 {{ $errors->has('username') ? $errors->first('username','<p><span class="label label-important">:message</span></p>') : '' }}
 </div>
 </div>
 <div class="control-group {{ $errors->has('email') ? 'error' : '' }}">
 {{ Form::label('email','Eメールアドレス',array('class'=>'control-label')) }}
 <div class="controls">
 {{ Form::text('email',Input::old('email')) }}
 {{ $errors->has('email') ? $errors->first('email','<p><span class="label label-important">:message</span></p>') : '' }}
 </div>
 </div>
 <div class="control-group {{ $errors->has('password') ? 'error' : '' }}">
 {{ Form::label('password','パスワード',array('class'=>'control-label')) }}
 <div class="controls">
 {{ Form::password('password') }}
 {{ $errors->has('password') ? $errors->first('password','<p><span class="label label-important">:message</span></p>') : '' }}
 </div>
 </div>
 <div class="form-actions">
 {{ Form::submit('新規登録',array('class'=>'btn btn-primary')) }}
 </div>
 </fieldset>
 {{ Form::close() }}
 </div>
@endsection

ルーター登録とモデルの作成

6. コントローラを作成する前にルーターにuserコントローラを登録します。

laravel/application/routes.php

//ルートの追加
 Route::controller(array('hello','home','collection','login','user'));

7. そしてUserモデルも作成します。

laravel/application/models/user.php

<?php
class User extends Eloquent{
}

8. これでuserコントローラを使う準備が整いましたので、ユーザーを登録する方法を調べてみましょう。

9. パスワードを登録するときに平文のままでは、セキュリティリスクが高すぎますので、Hashクラスのmakeメソッドでパスワードをハッシュします。

$pass=Hash::make(‘パスワード文字列’);

10. ハッシュしたパスワードと値を比較したいときには、checkメソッドを使います。第1引数に比較したい値(パスワード)、第2引数にハッシュしたパスワードを指定します。

Hash::check(比較したい値,$pass);

Userコントローラの作成

11. それでは、実際にコントローラを作成してみましょう。indexアクションとcreateアクションを下記のように作成します。

laravel/application/controllers/user.php

class User_Controller extends Base_Controller{
//トップページ
 public function action_index(){
 //EloquentORMで降順データの取得
 $page=User::order_by('created_at','desc')->paginate(10);
 $view=View::make('user.index');
 $view->users=$page->results;
 $view->links=$page->links();
 return $view;
 }
 //ユーザーの新規作成
 public function action_create(){
 //データ送信されたら
 if($input=Input::all()){
 //バリデーションルールの定義
 $rules=array(
 'username'=>'required|between:4,50',
 'email'=>'required|email|unique:users,email',
 'password'=>'required|alpha_num|between:4,16'
 );
 //バリデーションをインスタンス化
 $val=Validator::make($input,$rules);
 //バリデーションNGなら
 if($val->fails()){
 //エラーと入力値をセットしてリダイレクト
 return Redirect::to('user/create')
 ->with_errors($val)
 ->with_input();
 }else{
 //データの整理
 $data['username']=Input::get('username');
 $data['email']=Input::get('email');
//受け取ったパスワードをハッシュしてセット
 $data['password']=Hash::make(Input::get('password'));
 //EloquentORMでデータの新規作成
 $create=User::create($data);
 //トップページへリダイレクト
 return Redirect::to('user/index');
 }
 }
 return View::make('user/create');
 }
}

12. データ登録後に移動するトップページのビューファイルを下記のように作成します。

laravel/application/views/user/index.blade.php

@layout('layouts.master')
@section('navigation')
 <li>{{ HTML::link('user/index','トップページ') }}</li>
 <li>{{ HTML::link('user/create','新規作成') }}</li>
@endsection
@section('content')
<table class="table table-striped table-bordered">
 <tr>
 <th>id</th>
 <th>ユーザー名</th>
 <th>Eメールアドレス</th>
 <th>パスワード</th>
 <th>作成日</th>
 <th>更新日</th>
 <th>処理</th>
 </tr>
@foreach($users as $user)
 <tr>
 <td>{{ $user->id }}</td>
 <td>{{ $user->username }}</td>
 <td>{{ $user->email }}</td>
 <td>{{ $user->password }}</td>
 <td>{{ $user->created_at }}</td>
 <td>{{ $user->updated_at }}</td>
 <td><i class="icon-pencil"></i>
 {{ HTML::link_to_action('user@edit','編集',array($user->id)) }}
 <i class="icon-remove"></i>
 {{ HTML::link_to_action('user@delete','削除',array($user->id)) }}</td>
 </tr>
@endforeach
</table>
{{ $links }}
@endsection

13. それでは、実際にユーザー登録してみましょう。

14. 登録後トップページへ移動して下記のように表示されました。

登録の確認のためにパスワードまで表示しましたが、実際の運用時にはパスワードは表示しないようにした方がいいでしょう

ログイン処理

15. それでは実際にログインするためにログインビューファイルを作成します。

laravel/application/views/user/login.blade.php 

@layout('layouts.master')
@section('navigation')
 <li>{{ HTML::link('user/index','トップページ') }}</li>
@endsection
@section('content')
<div class="row">
<div class="alert alert-info">
<h4>ログインページです</h4>
</div>
 {{ Form::open(URL::current(),'POST',array('class'=>'form-horizontal')) }}
 <fieldset>
 <div class="control-group {{ $errors->has('email') ? 'error' : '' }}">
 {{ Form::label('email','Eメールアドレス',array('class'=>'control-label')) }}
 <div class="controls">
 {{ Form::text('email',Input::old('email')) }}
 {{ $errors->has('email') ? $errors->first('email','<p><span class="label label-important">:message</span></p>') : '' }}
 </div>
 </div>
 <div class="control-group {{ $errors->has('password') ? 'error' : '' }}">
 {{ Form::label('password','パスワード',array('class'=>'control-label')) }}
 <div class="controls">
 {{ Form::password('password') }}
 {{ $errors->has('password') ? $errors->first('password','<p><span class="label label-important">:message</span></p>') : '' }}
 </div>
 </div>
 <div class="form-actions">
 {{ Form::submit('ログイン',array('class'=>'btn btn-primary')) }}
 </div>
 </fieldset>
 {{ Form::close() }}
 </div>
@endsection

16. ルートにフィルターを作成します(uesrという名前のフィルターを作成します)。このフィルターはログインしていなければ強制的にuser/loginページへリダイレクトします。

laravel/application/routes.php

Route::filter('user',function(){
 if(Auth::guest()) return Redirect::to('user/login');
 });

17. そして、userコントローラの一番最初の方にコンストラクターを追加し、loginとlogout以外に上記のフィルターを適用します。

laravel/application/controllers/user.php

//コンストラクター
 function __construct(){
 parent::__construct();
 //login,logout以外に'user'フィルターを適用する
 $this->filter('before','user')->except(array('login','logout'));
 }

18. 同じくuserコントローラの最後の方にloginアクションとlogoutアクションを作成します。

//ログイン
 public function action_login(){
 //データ送信されたら
 if($input=Input::all()){
 //バリデーションルールの定義
 $rules=array(
 'email'=>'required|email',
 'password'=>'required|alpha_num|between:4,16'
 );
 //バリデーションをインスタンス化
 $val=Validator::make($input,$rules);
 //バリデーションNGなら
 if($val->fails()){
 //エラーと入力値をセットしてリダイレクト
 return Redirect::back()
 ->with_errors($val)
 ->with_input();
 //バリデーションOKなら
 }else{
 //データの整理
 $data['username']=Input::get('email');
 $data['password']=Input::get('password');
 if(Auth::attempt($data)){
 //トップページへリダイレクト
 return Redirect::to('user/index');
 }
 }
 }
 return View::make('user/login');
 }
 //ログアウト
 public function action_logout(){
 Auth::logout();
 return Redirect::to('user/login');
 }

19. これでloginとlogout以外は認証していなければアクセスできないようになりました。

20. それでは、ブラウザで確認してみます。まず、バリデーションを確認してみます。きちんとバリデーションされています。

21. 正しい、Eメールアドレスとパスワードでログインしてみます。きちんとログインされていればOKです。

navigationの『ログアウト』リンクと『ようこそユーザー名』の箇所はご自身で作成して下さい。ユーザー名はAuthクラスのuserメソッドを使用すれば、ユーザーモデルにアクセスできます。

尚、現状『編集』と『削除』のリンク先のアクションはまだ作成していませんので、エラーになります。その辺のアクション及びビューもそんなに難しくないと思いますので、ご自身で勉強がてら作成してみて下さい。

22. LaravelのAuthクラスは、単純な認証しか対応していないみたいです。groupやrole等(アクセスユーザーによってページや処理の権限を変更する)が必要な場合は自身で作成するか、Laravelユーザーの有志が提供しているbundleを利用する必要があります。その辺のところは余裕が出来たら調べてみたいと思います。

本日は以上です。

モデル内にセッターの指定

川瀬様より貴重なご意見を頂戴致しましたので、早速採用させていただきたいと思います。

23. Userモデル内にパスワードをハッシュするセッターを作成します。このセッターはパスワードをモデルのプロパティにセットするときにこのメソッドが呼び出されます。つまり、ハッシュしたパスワードをモデルのプロパティにセットします。

laravel/application/models/user.php

<?php
class User extends Eloquent{
 //パスワードのハッシュ
 public function set_password($password){
 $this->set_attribute('password',Hash::make($password));
 }
}

24. そして、11.のuserコントローラのcreateアクションの30~34行目を下記のように修正します。3行のコードがたった1行で書けるようになります。

//データのセット
 $data=Input::only(array('username','email','password'));

これで、川瀬様のご指摘通りハッシュし忘れもなくなりますし、コードもすっきりします。

川瀬様 ありがとうございました。

このエントリーを含むはてなブックマーク Buzzurlにブックマーク livedoorクリップ Yahoo!ブックマークに登録

トラックバック&コメント

この投稿のトラックバックURL:

トラックバック

コメント

  1. HiroKws より:

    こんにちは。
    多分Userモデルにセッターを指定してあげたほうが、ハッシュのし忘れを防げますので、良いでしょう。

    class User extends Eloquent{
    public function set_password($password)
    {
    $this->set_attribute(‘password’, Hash::make($password));
    }
    }

    モデル中のクラス名でset_フィールド名を作成すると、そのフィールドに対する代入時に、作成したメソッドが呼び出されます。
    このメソッドの中で’password’フィールドに、ハッシュ値を設置します。

    • nakada より:

      川瀬 様
      貴重なご意見ありがとうございます。
      早速採用させていただきました。
      これからもよろしくお願いいたします。


コメントをどうぞ

このページの先頭へ