Fuelphpのsimpleauthについては、既に日本語の記事が上がっておりますが、サンプル+テストプログラムはいくつあっても理解のじゃまになりません。そこで、私も作って見ました。
追記:たくさんアクセスいただいているようですが、どうしてもコードが変わってしまうので修正は諦め、Githubにのせました。
fuelphp_simpleauth_sample_for_1_1
こちらから、ソースを落として、お試しください。この記事とは多少変更していますが、コメント入っているので、参考にしてください。
(Fuelphp version 1.1-RC1で確認したソースを載せています。1.1の正式版がリリースされました。紹介しているコードについて、正式版と、RC版で、一箇所修正が必要です。設定ファイルであるsimpleauth.php中、コントローラー/アクションとロールの紐付けを宣言している部分で、RC版ではコントローラーの先頭に/バックスラッシュ、もしくは円記号が必要です。正式版では必要有りません。RC版で付けなかったり、正式版で付けると、認証されません。)
(追記:実際にこのsimpleauthを利用して、サイトを作っている途中ですが、セッションのフラッシュデーターを利用して、バリデーションのメッセージを出している処理で、メッセージによってはクッキーの4KBを超えるというエラーで止まってしまいます。実用的には、セッションはファイルかDBへ保存するでしょうから、その設定方法は別記事で紹介しています。。)
(追記:このサイトで使っているエディターがバグっており、プログラムコードが乱れたり、行が抜けたりしています。気がついたら修正しているのですが、勝手に思わない所で書き変わっているので、気が付かないこともあります。)
方針は、1.多国語化については前回の記事で簡単に説明してあるので、考えない。(メッセージ等を日本語にして、読みやすくする。)2.実際の動作が、目に見えるデモをつくる。3.一応、入力のバリデーションは、まじめにやる。4.Corntroller_Templateを使ってみる。
そんな感じで、Stationwagonとoilが生成したコードを参考に、組んで見ました。しばらく、プログラムをやっていませんし、PHPで推奨されるような書き方をしていないかも知れません。ご了承ください。
なお、SimpleAuthについての説明は、9nensanさんの、FuelPHPで作るログイン管理という記事が参考になります。
最初に、Fuelをインストールしたら、最初にHello世界などの、余計なコードは消しておきましょう。
まずは、コンフィグファイルから、設定して行きましょう。
SimpleAuthはユーザー情報をDB上に置きます。ACLやグループもFuel自体の認証では、考慮されているようですが、SimpleAuthでは、コンフィグファイルの中に記述し、DBは使いません。ユーザー情報のみをDBにのせます。Fuelのような、ライトウェイトなフレームワークを利用する状況は、柔軟にグループやACLを活用することはないでしょうし、オーバーヘッドを考えるなら、このくらいが丁度よいかも知れませんね。
続いて、DBの設定ファイルです。何も設定しなければ、開発モードです、開発モード中はapp/config/development/db.phpがまず、読み込まれます。(正確に言うと、ここで設定されていない項目は、app/config/db.php、そしてcoreの中のコンフィグファイル中の設定となりますから、読み込み順序としては、逆かも知れませんね。仕組みは調べていませんけれど。)
では、db.phpの内容です。
<?php
/**
* The development database settings.
*/
return array(
'default' => array(
'connection' => array(
'dsn' => 'mysql:host=localhost;dbname=DBの名前',
'username' => 'ユーザー名',
'password' => 'パスワード',
),
),
);
皆さんの環境や設定、お好みに合わせて調整してください。
続いてapp/config/config.phpです。内容は長いですから、全部は紹介しません。今回のテストのためには、Authパッケージだけ有効になっていれば、結構です。以下の部分を修正してください。
'always_load' => array(
/**
* These packages are loaded on Fuel's startup. You can specify them in
* the following manner:
*
* array('auth'); // This will assume the packages are in PKGPATH
*
* // Use this format to specify the path to the package explicitly
* array(
* array('auth' => PKGPATH.'auth/')
* );
*/
'packages' => array(
// 'orm',
'auth',
),
ルーティングを設定しましょう。FuelのデフォルトはCIと同じく、Class/Action/...です。今回はコントローラーとしてTestクラスを作成して、デモを作成しました。404の扱いもTestクラスの中でやっています。
app/config/route.phpの中身は、以下のようにシンプルです。
<?php
return array(
'_root_' => 'test/index', // デフォルトページ(トップドメインへのアクセス時)の設定
'_404_' => 'test/404', // 404ページ
);
次に紹介するのが、キモになるSimpleAuth自身の設定ファイルです。もともとは、packages/auth/config/simpleauth.phpにありますが、このパッケージを使用するときに、app/configにコピーして、内容を変更します。
<?php /**
* Fuel is a fast, lightweight, community driven PHP5 framework.
*
* @package Fuel
* @version 1.0
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2011 Fuel Development Team
* @link http://fuelphp.com
*/
return array(
/**
* DB connection, leave null to use default
*/
'db_connection' => null,
/**
* DB table name for the user table
*/
'table_name' => 'users',
/**
* Choose which columns are selected, must include: username, password, email, last_login,
* login_hash, group & profile_fields
*/
'table_columns' => array('*'),
/**
* This will allow you to use the group & acl driver for non-logged in users
*/
'guest_login' => true,
/**
* グループid => array('name' => 'グループ表示名', 'roles' => array(適用されるロール名)
*/
'groups' => array(
/**
* Examplesと同様のグループ構成
*/
-1 => array('name' => 'Banned', 'roles' => array('banned')),
0 => array('name' => 'Guests', 'roles' => array()),
1 => array('name' => 'Users', 'roles' => array('user')),
50 => array('name' => 'Moderators', 'roles' => array('user', 'moderator')),
100 => array('name' => 'Administrators', 'roles' => array('user', 'moderator', 'admin')),
1000 => array('name' => 'Super', 'roles' =>array('super')),
),
/**
* 役割名 => array(location => rights)
*/
'roles' => array(
/**
* Examplesを元に作成
*/
// 全グループに一致、つまりゲストアクセス可
'#' => array(
'\Controller_Test' => array(// コントローラー
'index', // アクション
'404', // 404ページのアクションをここに登録しないと、表示されない。はまりどころ。
),
),
// ユーザー、つまり一般ユーザーとしてログイン後、アクセス可
'user' => array(
'\Controller_Test' => array(// コントローラー
'user', // アクション
),
),
// モデレーターとしてログイン後、アクセス可
'moderator' => array(
'\Controller_Test' => array(
'moderator', // アクション
)
),
// 管理者としてログイン後、アクセス可
'admin' => array(
'\Controller_Test' => array(// コントローラー
'admin',) // アクション
),
// アクセス拒否(banned)
'banned' => false,
// 全アクセス許可(super)、使用注意!
'super' => true,
),
/**
* login hashのソルト
*/
'login_hash_salt' => 'ShooopaizZ03Gidple',
/**
* $_POST キー :ログインページのユーザー名入力項目名
*/
'username_post_key' => 'username',
/**
* $_POST キー:ログインページのパスワード入力項目名
*/
'password_post_key' => 'password',
);
コメントたくさん入れてあります。ポイントとなる考え方は、ロールごとに、どのコントローラーの、どのアクションが出来るのかを割りつけることです。今回の例では、コントローラー、アクション共にほとんどのパターンで、1つずつしか指定していませんが、当然お好きなだけ、指定できます。もちろん、対象となるコントローラーの中で、認証をチェックするコードを実行しますが、この認証を行なっているのに、どのロールにもそのアクションが割りつけられていないと、誰も実行できなくなります。テストプログラムの中に、入れてあります。後ほど、ご自身で確かめてください。(ただし、superロールは、割付が行われていないコントローラー/アクションにもアクセスできます。)
あと、はまったのは、このデモでおこなったように、404時に指定したアクションを認証が必要とするクラスで書く場合は、全グループがアクセス可のロールに割りつけていないと、表示され無くなります。まあ、404を認証が必要なクラスでは、書かないというのが、本筋ではありますね。
注意:1.1RC版では紹介したコードのように、コントローラー名の先頭にバックスラッシュか円記号が必要です。1.1正式版ではつけてはいけません。外してください。
これでコンフィグファイルの設定はおしまいです。認証に必要なユーザーのDBを作成しましょう。
FuelのHPのドキュメントにSQLが書かれています。そのまま転記します。
CREATE TABLE `users` (
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`username` VARCHAR( 50 ) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL ,
`password` VARCHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL ,
`group` INT NOT NULL DEFAULT 1 ,
`email` VARCHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL ,
`last_login` VARCHAR( 25 ) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL ,
`login_hash` VARCHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL ,
`profile_fields` TEXT CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL ,
`created_at` INT( 11 ) UNSIGNED NOT NULL ,
UNIQUE (
`username` ,
`email`
)
)
これを実行して、usersテーブルを予め作成しておきましょう。
次にコントローラーです。
最初に、Authクラスです。プレフィックスにController_が付きます。正確に言えば、コントローラーをcontrollersフォルダーの下に置いているためです。クラス名はアンダーバーで区切られたディレクトリー構成に沿って表されます。オートロードのための「規約」の部分です。コードは、こんな感じです。app/classes/controller/auth.phpです。
<?php
class Controller_Auth extends Controller_Template
{
function action_login()
{
if (Input::method() == 'POST')
{
// バリデーションの準備
$val = Validation::forge();
// バリデーションルール
$val->add('username', 'ユーザー名')
->add_rule('required')
->add_rule('min_length', 3)
->add_rule('max_length', 20);
$val->add('password', 'パスワード')
->add_rule('required')
->add_rule('min_length', 3)
->add_rule('max_length', 20);
// バリデート
if ($val->run())
{
// バリディート成功、ユーザー認証処理
if (Auth::instance()->login($val->validated('username'), $val->validated('password')))
{
Session::set_flash('notice', '認証されました');
Response::redirect('test');
}
else
{
Session::set_flash('notice', 'ユーザー名かパスワードに間違いがあります。');
}
}
else
{
// バリデート失敗
Session::set_flash('notice', $val->errors());
}
}
$this->template->title = 'ログイン';
$this->template->content = View::forge('login');
}
function action_register()
{
if (Input::method() == 'POST')
{
// バリデーションの準備
$val = Validation::forge();
// バリデーションルール
$val->add('username', 'ユーザー名')
->add_rule('required')
->add_rule('min_length', 3)
->add_rule('max_length', 20);
$val->add('password', 'パスワード')
->add_rule('required')
->add_rule('min_length', 3)
->add_rule('max_length', 20);
$val->add('password_confirm', 'パスワード確認')
->add_rule('required')
->add_rule('min_length', 3)
->add_rule('max_length', 20)
->add_rule('match_field', 'password'); // パスワードと一致
$val->add('email', 'メールアドレス')
->add_rule('required')
->add_rule('valid_email');
// バリデート
if ($val->run())
{
// グループIDを求める。いきなりマジックナンバーが出てくるのは気持ち悪いが、
// 説明を簡単にするためには仕方ない。1,50,100、1000という数字は、add/config/simpleauth.phpの
// 中で決めている、グループ番号
$group_id = array_search(Input::post('role'), array(1 => 'user', 50 => 'moderator', 100 => 'admin', 1000=>'super'));
$group_id = $group_id ? $group_id : 1;
// ユーザーの登録
if (Auth::instance()
->create_user($val->validated('username'), $val->validated('password'), $val->validated('email'), $group_id))
{
Session::set_flash('notice', '登録されました。ありがとうございます。');
Response::redirect('test');
}
else
{
throw new Exception('予期しないエラーが起きました。再度、登録をお願いします。');
}
}
else
{
// バリデート失敗
Session::set_flash('notice', $val->errors());
}
}
$this->template->title = 'ユーザー登録';
$this->template->content = View::forge('register');
}
function action_logoff()
{
Auth::instance()->logout();
Session::set_flash('notice', 'ログオフしました。');
Response::redirect('test');
} }
メッセージは日本語にしましたし、コメントもたくさん入れておきました。ユーザー登録の際に、グループを指定できるようにしています。もちろん、本番環境では、そんな仕様にしないでください。このデモでしたら、userグループのidである1を指定して、ユーザー登録しましょう。
ビューを先に紹介しておいたほうがいいですね。
Controllerクラスではなく、その派生クラスのController_Templateを利用する場合、デフォルトで、app/views/template.phpがテンプレートとして利用されます。今回はoilが生成してくれたものを、そのまま利用しました。
<!DOCTYPE html> <html>)) : ?>
<head>
<meta charset="utf-8">
<title></title>
<style type="text/css">
* { margin: 0; padding: 0; }
body { background-color: #EEE; font-family: sans-serif; font-size: 16px; line-height: 20px; margin: 40px; }
#wrapper { padding: 30px; background: #fff; color: #333; margin: 0 auto; width: 600px; }
a { color: #36428D; }
h1 { color: #000; font-size: 55px; padding: 0 0 25px; line-height: 1em; }
.intro { font-size: 22px; line-height: 30px; font-family: georgia, serif; color: #555; padding: 29px 0 20px; border-top: 1px solid #CCC; }
.notice { border: 1px solid #CCC; padding: 10px; background-color: #EEE; }
h2 { margin: 50px 0 15px; padding: 0 0 10px; font-size: 18px; border-bottom: 1px dashed #ccc; }
h2.first { margin: 10px 0 15px; }
p { margin: 0 0 15px; line-height: 22px;}
a { color: #666; }
pre { border-left: 1px solid #ddd; line-height:20px; margin:20px; padding-left:1em; font-size: 16px; }
pre, code { color:#137F80; font-family: Courier, monospace; }
ul { margin: 15px 30px; }
li { line-height: 24px;}
label { display: block; }
.footer { color: #777; font-size: 12px; margin: 40px 0 0 0; }
</style>
</head>
<body>
<div id="wrapper">
<h1>
isset(Session::get_flash('notice')
<div class="notice"><p><?php echo implode('</p><p>', (array) Session::get_flash('notice')); ?></div></p>
<?php endif; ?>
</h1>
<?php echo $content; ?> <p class="footer">
<a href="http://fuelphp.com">Fuel</a> is released under the MIT license.<br />Page rendered in {exec_time}s using {mem_usage}mb of memory.
</p>
</div>
</body>
</html>
続いて、ログインフォームです。app/views/login.phpです。
<?php echo Form::open(); ?>
<p>
<?php echo Form::label('ユーザー名', 'username'); ?>
<?php
echo Form::input(
'username', Input::post('username', isset($post) ? $post->username : ''), array('size' => 30));
?>
</p>
<p>
<?php echo Form::label('パスワード', 'password'); ?>
<?php
echo Form::password(
'password', Input::post('password', isset($post) ? $post->password : ''), array('size' => 30));
?>
</p>
<div class="actions">
ユーザー登録フォーム、app/views/register.phpです。
echo Form::input(
'username', Input::post('username', isset($post) ? $post->username : ''), array('size' => 30));
?>
echo Form::password(
'password', Input::post('password', isset($post) ? $post->password : ''), array('size' => 30));
?>
echo Form::password(
'password_confirm', Input::post('password_confirm', isset($post) ? $post->password_confirm : ''), array('size' => 30));
?>
echo Form::input(
'email', Input::post('email', isset($post) ? $post->email : ''), array('size' => 30));
?>
$checked = array_search(Input::post('role', isset($post) ? $post->role : 'user'),
array('user'=>'user', 'moderator'=>'moderator', 'admin'=>'admin', 'super'=>'super'));
$checked = $checked ? $checked : 'user';
?>
'checked') : array()); ?>
'checked') : array()); ?>
'checked') : array()); ?>
'checked') : array()); ?>
</p>
<div class="actions">
<?php echo Form::submit('register', 'ユーザー登録'); ?>
</div>
<?php echo Form::close(); ?>
コントローラーに戻ります。デモの本体部分です。Testクラスです。app/classes/controller/test.phpです。
<?php
class Controller_Test extends Controller_Template
{
/*
* 理解しやすいようにここに記述したが、本来は
* Controller_Templateクラスを拡張したクラスで、
* このbeforeだけを行い、
* 実際のコントローラークラスは、その拡張したクラスを
* 継承したほうが、正解。
* 参考は、ステーションワゴンのサンプル。
*/
public function before()
{
parent::before();
// コントローラーとアクションから、アクセス権チェック
$access = Auth::has_access(array(
$this->request->controller,
$this->request->action
));
if ($access == true)
{
// アクセス権有り、続いてログインしているかチェック
if (Auth::check())
{
// ログイン中
$this->user_id = Auth::instance()->get_user_id();
$this->user_id = $this->user_id[1];
}
}
else
{
// アクセス権なし
Session::set_flash('notice', 'このアドレスへアクセスする権限を持っていません。');
Response::redirect('test');
}
}
// 以下のアクション(action_index~action_404)に対する、ロールの割付は、
// add/config/simpleauth.phpの中で行われている。
function action_index()
{
$this->template->title = ' Index(デフォルト)アクション';
$this->template->content = View::forge('testnow');
}
function action_user()
{
$this->template->title = 'User(ユーザー)アクション';
$this->template->content = View::forge('testnow');
}
function action_moderator()
{
$this->template->title = 'Moderator(モデレーター)アクション';
$this->template->content = View::forge('testnow');
}
function action_admin()
{
$this->template->title = 'Admin(管理者)アクション';
$this->template->content = View::forge('testnow');
}
function action_no_role()
{
$this->template->title = 'No Role(割付なし)アクション';
$this->template->content = View::forge('testnow');
}
public function action_404()
{
$messages = array('ごめんなさい…', '残念!', 'なんてこったい…', 'ココはどこ…?', 'あれれ?!');
$messages = $messages[array_rand($messages)];
// Set a HTTP 404 output header
$this->response->status = 404;
$this->template->title = $messages;
$this->template->content = View::forge('404');
}
}
このテストのためのビューです。app/views/testnow.phpです。
<p>認証テストページ</p>
<p>
<?php
// 認証されている=ログインしているかチェック
if (Auth::check())
{
// ログイン済み
// ユーザーid取得
$user_id = Auth::instance()->get_user_id();
echo 'User Id: ' . $user_id[1] . ', ';
// ユーザー名取得
echo 'Name: ' . Auth::instance()->get_screen_name() . ', ';
// グループid取得
$group = Auth::instance()->get_groups();
echo 'Group#: ' . $group[0][1] . ', ';
// グループ名取得
$group_config = Config::get('simpleauth.groups');
echo 'Group Name:' . $group_config[$group[0][1]]['name'] . '<br>';
echo Html::anchor('auth/logoff', 'ログオフ');
echo ' ';
}
else
{
// 未ログイン
echo Html::anchor('auth/login', 'ログイン');
echo ' ';
echo Html::anchor('auth/register', 'ユーザー登録');
}
?>
</p>
<div>
<p> <?php echo Html::anchor('test/index', 'ゲストロール'); ?></p>
<p> <?php echo Html::anchor('test/user', 'ユーザーロール'); ?></p>
<p> <?php echo Html::anchor('test/moderator', 'モデレーターロール'); ?></p>
<p> <?php echo Html::anchor('test/admin', '管理者ロール'); ?></p>
<p> <?php echo Html::anchor('test/no_role', 'ロール割付なし'); ?></p>
</div>
(追記:ログインユーザーの情報が表示されるように変更しました。)
最後に404ページ。app/views/404.phpです。
<p>お探しのページは存在していません。</p>
以上で、全ファイルです。
ルーティングをconfig/routes.phpで設定しTest/index(クラスController_Testのaction_index関数)へブラウザでアクセスしてください。各グループのユーザーを登録し、そのユーザーで認証が必要なページへアクセスすれば、そのグループに割りつけられた、ロールに応じて、アクセス許可・拒否されるのが、わかると思います。メッセージも、わかりやすく、出しておきました。
| SimpleAuthをシンプルに解説< 前 | 次 >Fuelphpをwindowsでもgitしやすくする |
|---|
| < 前 | 次 > |
|---|