Zend Framework:テンプレートエンジンをSmartyにするのサンプルに、認証が必要なページを追加してみます。
Zend_Aclを使って、ページへのアクセスが可能かチェックします。
認証は、Zend_Authを使ってみます。
前提
今回のサンプルは、データベースを使用します。
データベースは、MySQL5以降です。
また、PDOを使用していますので、PDO_MYSQLがPHPに組み込まれている必要があります。
PHP5.2.3をソースからインストールする場合のconfigureの例です。
--with-pdo-mysqlを指定して、PDOを組み込んでいます。
# ./configure \\
--with-apxs2 \\
--with-mysql=/usr/mysql \\
--with-config-file-path=/etc/php \\
--enable-mbstring \\
--with-zlib \\
--with-gd \\
--with-libmbfl \\
--with-jpeg-dir=/usr/lib \\
--with-png-dir=/usr/lib \\
--with-dom \\
--enable-mbregex \\
--without-pear \\
--enable-gd-native-ttf \\
--enable-bcmath \\
--enable-exif \\
--with-pdo-mysql=/usr/mysql
アクセス制御
次のようなアクセス制御を行うようにします。
ログインしていないユーザーは、anonymousというグループに所属するものとします。
anonymousグループに所属するユーザーは、トップページのようなログインを必要としないページのみを表示できます。
memberというグループに所属するユーザーは、次のページを表示できます。
/index/member
また、anonymousグループがアクセスできるページも表示できます。
adminというグループに所属するユーザーは、次のページを表示できます。
/index/admin
また、memberグループがアクセスできるページも表示できます。
サンプルのアクセス制御のソース
アクセスできるかどうかのチェックを、アクションコントローラのpreDispatchメソッドで行うようにしてみます。
-
<?php
-
abstract class Custom_Default_Controller_Action extends Tz_Controller_Action
-
{
-
-
protected $_userInfo = null;
-
-
public function init()
-
{
-
parent::init();
-
}
-
-
public function preDispatch()
-
{
-
parent::preDispatch();
-
-
$this->_checkAcl();
-
}
-
-
/**
-
* 要求されたアクションにアクセスできるかチェックする。
-
* アクセス許可されていない場合は、ログイン画面を表示する。
-
*/
-
private function _checkAcl()
-
{
-
$registry = Zend_Registry::getInstance();
-
$auth = new Zend_Session_Namespace('auth');
-
$this->_userInfo = $this->_getUserInfo($auth->user_id);
-
}
-
}
-
else {
-
// DB接続にエラーがあった場合は、認証情報をクリアーしておく
-
Zend_Session::namespaceUnset('auth');
-
}
-
-
require_once 'Zend/Acl.php';
-
require_once 'Zend/Acl/Role.php';
-
require_once 'Zend/Acl/Resource.php';
-
-
$acl = new Zend_Acl();
-
$acl->add(new Zend_Acl_Resource('index'));
-
-
$acl->addRole(new Zend_Acl_Role('anonymous'));// anonymousロールは、ログインしていないユーザー
-
$acl->addRole(new Zend_Acl_Role('member'), 'anonymous');// memberロールは、ログインしたユーザー
-
$acl->addRole(new Zend_Acl_Role('admin')); // adminロールは、すべてにアクセス可能なユーザー
-
-
// 誰でもアクセス可能なindexコントローラのアクションの設定
-
$acl->allow('anonymous', 'index', 'index');
-
$acl->allow('anonymous', 'index', 'throw');
-
$acl->allow('anonymous', 'index', 'test');
-
-
// memberロールを持ったユーザーのみアクセス可能なindexコントローラのアクションの設定
-
$acl->allow('member', 'index', 'member');
-
-
// Logon,Error,Sorryコントローラへは誰でもアクセス可能
-
$acl->add(new Zend_Acl_Resource('logon'));
-
$acl->allow(null, 'logon');
-
$acl->add(new Zend_Acl_Resource('error'));
-
$acl->allow(null, 'error');
-
$acl->add(new Zend_Acl_Resource('sorry'));
-
$acl->allow(null, 'sorry');
-
-
// adminはすべてアクセス許可
-
$acl->allow('admin');
-
-
$request = $this->getRequest();
-
$controller = $request->getControllerName();
-
$action = $request->getActionName();
-
-
$role = 'anonymous';
-
}
-
else {
-
$role = $this->_userInfo->role;
-
}
-
-
$is_allowed = false;
-
if ($acl->has($controller)) {
-
$is_allowed = $acl->isAllowed($role, $controller, $action);
-
}
-
else {
-
if ($role == 'admin') {
-
$is_allowed = true;
-
}
-
}
-
-
if (!$is_allowed) {
-
// Logonコントローラに現在のリクエストオブジェクトのコピーを渡すための処理。
-
// (ログイン後、元のリクエストに対応するページを表示する情報となる)
-
$front = $this->getFrontController();
-
$dipatcher = $front->getDispatcher();
-
$dipatcher->setParam('originalRequest',clone $request);
-
-
// ログイン画面を表示する
-
$this->_forward('index','logon');
-
}
-
else {
-
// アクセス権限がない旨を表示する画面に移動
-
$this->_redirect('/sorry');
-
}
-
}
-
}
-
-
/**
-
* ユーザーIDに対応するユーザー情報を取得する。
-
*/
-
private function _getUserInfo($user_id)
-
{
-
$webapp_dir = $this->_registry['webappDir'];
-
require_once $webapp_dir . '/modules/default/models/table/Users.php';
-
-
$table = new Table_Users();
-
$rowset = $table->find($user_id);
-
if ($rowset->count()) {
-
return $rowset->current();
-
}
-
return false;
-
}
-
}
ログインしていないユーザーが、ログインが必要なページにアクセスしたとき、ログインページを表示するようにしています。
認証
Zend_Auth_Adapter_DbTableを使用して、認証を行ってみます。
データベース上のユーザー情報を格納したテーブルを参照することになります。
ユーザー情報テーブル
passwordカラムには、MD5でハッシュ化した値を格納します。
-
CREATE TABLE `td_users` (
-
`user_id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
-
`role` varchar(128) NOT NULL,
-
`username` varchar(128) NOT NULL,
-
`email` varchar(128) NOT NULL,
-
`password` varchar(128) NOT NULL,
-
`updatetime` datetime DEFAULT NULL,
-
`createtime` datetime DEFAULT NULL,
-
PRIMARY KEY (`user_id`),
-
UNIQUE KEY `username` (`username`)
-
) ENGINE=MyISAM DEFAULT CHARSET=utf8
次のようなユーザー情報が格納されます。
-
+---------+--------+-----------+-------------------+----------------------------------+------------+------------+
-
| user_id | role | username | email | password | updatetime | createtime |
-
+---------+--------+-----------+-------------------+----------------------------------+------------+------------+
-
| 1 | admin | adminuser | admin@localdomain | 25e4ee4e9229397b6b17776bfceaf8e7 | | |
-
| 2 | member | testuser | test@localdomain | 179ad45c6ce2cb97cf1029e212046e81 | | |
-
+---------+--------+-----------+-------------------+----------------------------------+------------+------------+
サンプルの認証のソース
-
<?php
-
-
class LogonController extends Custom_Default_Controller_Action
-
{
-
const SESS_NAME_FORM_OPT = 'form_opt';
-
-
private $_sessFormOpt = null;
-
-
public function init()
-
{
-
parent::init();
-
-
$this->_sessFormOpt = new Zend_Session_Namespace(self::SESS_NAME_FORM_OPT);
-
-
// Logonコントローラに来る前にアクセ時のrequestオブジェクト
-
$original_request = $this->getInvokeArg('originalRequest');
-
if ($original_request) {
-
$this->view->assign('original_path',$original_request->getPathInfo());
-
}
-
}
-
-
public function indexAction()
-
{
-
$sess_form_opt = new Zend_Session_Namespace('form_opt');
-
$sess_auth = new Zend_Session_Namespace('auth');
-
-
$request = $this->getRequest();
-
-
$username = $request->getPost('username');
-
$this->_redirect('/');
-
exit;
-
}
-
$this->_resetToken();
-
return;
-
}
-
-
$token = $request->getPost('token');
-
if ($token != $sess_form_opt->token) {
-
$this->view->assign('result_msg','トークンのチェックに失敗しました。');
-
-
$this->_resetToken();
-
return;
-
}
-
-
$password = $request->getPost('password');
-
-
// 入力値をチェック
-
require_once 'Zend/Validate/Alnum.php';
-
$v = new Zend_Validate_Alnum();
-
if (!$v->isValid($username)) {
-
$this->view->assign('result_msg','ユーザー名に英数字を入力してください。');
-
$this->_resetToken();
-
return;
-
}
-
$v = new Zend_Validate_Alnum();
-
if (!$v->isValid($password)) {
-
$this->view->assign('result_msg','パスワードに英数字を入力してください。');
-
$this->_resetToken();
-
return;
-
}
-
-
require_once 'Zend/Auth/Result.php';
-
require_once 'Zend/Auth/Adapter/DbTable.php';
-
-
$result = false;
-
try {
-
$zdb_adapter = Zend_Registry::get('zdb_adapter');
-
-
$adapter = new Zend_Auth_Adapter_DbTable($zdb_adapter, 'td_users', 'username', 'password','MD5(?)');
-
$adapter->setIdentity($username);
-
$adapter->setCredential($password);
-
-
$result = $adapter->authenticate();
-
}
-
catch (Exception $exception) {
-
$this->view->assign('result_msg','エラーです。' . $exception->getMessage());
-
$this->_resetToken();
-
return;
-
}
-
-
if ($result && $result->isValid()) {
-
$id = $result->getIdentity();
-
$row_obj = $adapter->getResultRowObject('user_id');
-
-
$sess_auth->user_id = $row_obj->user_id;
-
-
$original_path = $request->getPost('original_path');
-
require_once 'Zend/Validate/Regex.php';
-
$v = new Zend_Validate_Regex('/^\/[a-zA-Z0-9\/]*$/');
-
if ($v->isValid($original_path)) {
-
$this->_redirect($original_path);
-
exit;
-
}
-
}
-
$this->_redirect('/');
-
}
-
else {
-
$this->_resetToken();
-
}
-
}
-
-
public function logoffAction()
-
{
-
Zend_Session::namespaceUnset('auth');
-
$this->_redirect('/');
-
}
-
-
private function _resetToken()
-
{
-
$sess_form_opt = $this->_sessFormOpt;
-
-
$this->view->assign('token',$token);
-
$sess_form_opt->token = $token;
-
}
-
}
サンプルダウンロード
ダウンロードページにアーカイブしたファイルを置きました。
データベースへのデータのインポート
データベースは、次のようなSQLで作成します。
mysql> CREATE DATABASE td06db CHARACTER SET utf8;
ユーザー名:tdtestuser、パスワード:tdtestuserで、td06dbデータベースにアクセスできるようにします。
mysql> GRANT ALL ON td06db.* to tdtestuser@localhost IDENTIFIED BY 'tdtestuser';
データは、次のようにtd06dbデータベースにインポートします(※)。
$ cd tdBASEDIR06/webapp06/sql
$ mysql -u tdtestuser -p td06db < td06db.sql
※ td_usersテーブルを作成して、そのテーブルにデータを挿入します。