【问题标题】:Design pattern for an authentication system in PHPPHP中身份验证系统的设计模式
【发布时间】:2013-10-21 21:08:01
【问题描述】:

我正在学习 PHP,我很好奇是否有优雅的解决方案来设计网站的身份验证界面。

基本上,我将拥有三种类型的用户:普通用户、管理员和“高级用户”。 每种类型的用户都有自己的操作。

这是我当前代码的简要草图:

# Regular User = Non-Authenticated
interface IRegularUser {
        # Will return an object of a class that implements this interface
        public static function loginUser ($name, $pass);
}

# Authenticated User
class AuthUser extends RegularUser {
        public function logoutUser();
}

interface IAdmin {..}
interface IPowerUser {...}
class User implements IRegularUser {}
class Admin     extends AuthUser implements IAdmin {}
class PowerUser extends AuthUser implements IPowerUser {}

在检查登录是否正确的脚本中,我会写类似这样的内容:

$user = new User();
$user = $user->loginUser($_POST['username'], $_POST['password']);

if (get_class($user) == get_class(new Admin()))
    # Redirect to admin_home.html   
else if (get_class($user) == get_class(new PowerUser()))
    # Redirect to power_user_home.html

我正在尝试使用 PHP 的 OOP 功能,以便在我的应用程序中的实体之间建立一些约束(例如:只有通过获取 User 对象,您才能登录,并获取 Admin 类型的对象,或者超级用户)。

我觉得我的身份验证系统有点笨拙,我想知道 webapp 身份验证系统是否有通用的设计模式。

【问题讨论】:

  • "我想知道 webapp 身份验证系统是否有通用的设计模式。"没有。你似乎有一个好的开始,为什么不开始呢?

标签: php authentication


【解决方案1】:

实际上,它并不像乍看起来那么容易。与用户打交道时有 3 个不同的方面,它们具有角色。您正在寻找的“系统”将由以下组件组成:

查询适配器

它负责查找与某个适配器匹配的记录。这可以查询几乎任何类型,无论是MySQL 表、XML 文件还是Mongo DB 集合。你所有的查询适配器都会实现这个接口:

interface QueryAdapter
{
    public function recordValid($username, $password);
}

访问控制列表 (ACL/RBAC)

它必须是单独的层,处理角色及其权限。通常

$roleManager = new RoleManager();
$roleManager->register(array(
   'admin'     => 'write, edit, read, delete',
   'user'      => 'view',
   'moderator' => 'write, edit, read'
));


$currentUser = get_that_from_session();

if ($roleManager->isAllowed($currentUser, 'write')) {
  // Allow writing
} else {
  echo 'You are not allowed to write';
}

存储适配器

它负责在$_SESSION 或$_COOKIE 中存储密码和令牌。如果用户点击记住我,那么您将把该信息存储在$_COOKIE,否则存储在$_SESSION。

典型工作流程

要将它们“连接”在一起,您可以这样写:(请记住,这是它的极其简化版本)

<?php

$queryAdapter = new Query_Adapter_MySQL($pdo); // or $mongo, whatever

if ($queryAdapter->rowExists($_POST['username'], $_POST['password'])) {

   $role = $queryAdapter->getRole(); // Let's assume that its "user"

   $roleManager = new RoleManager();
   $roleManager->register(array(
      $role => 'read'
   ));

   if (isset($_POST['rememberMe'])){
      $storageAdapter = new StorageAdapter_Cookie();
   } else {
      $storageAdapter = new StorageAdapten_Session();
   }

   $storageAdapter->write(array(
      'role' => $role,
      'passwordHash' => $passwordHash,
      'token' => $token
   ));
}

要检查该用户是否已登录并有权执行某项操作,您只需查询适配器即可查看,例如,

<?php

if ($storageAdapter->isLoggedIn()){

   if ($roleManager->hasRight($storageAdapter->get('role'), 'read')){
      // Allowed to read content
   }
}

您将通过这种方法获得什么?

  • 明确的职责分离(这符合单一职责原则)
  • 提高了代码的可读性
  • 坚持依赖注入(从而使单元测试成为可能)
  • 您可以轻松地从 MySQL 切换到另一个存储,而不会影响其余代码。您只需注入您要使用的适配器的一个实例。

是这样吗?

是的。也可以看看Zend Framework如何implements this

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-21
    • 1970-01-01
    • 1970-01-01
    • 2012-12-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多