3

我有一个关于存储相当复杂的应用程序逻辑的最佳位置的问题。

假设我想允许用户登录该站点。登录过程应包括以下步骤:

  1. 从表单字段中,对用户的电子邮件进行哈希处理
  2. 在 auth 表中查找用户的电子邮件哈希以确保用户存在(auth 表仅存储加密的电子邮件、电子邮件哈希、user_id 和密码哈希)
  3. 如果找到用户,则验证他们的密码
  4. 重新生成会话 ID
  5. 将新会话存储在数据库中

使用数据映射器模式,我有以下三个模型参与此过程

/User/
 - User.php
 - UserMapper.php

/Auth/
 - Auth.php
 - AuthMapper.php

/Session/
 - Session.php
 - SessionMapper.php

因此,让用户登录的函数看起来像这样:

function login($email, $password)
{
    $security = new \Lib\Security;
    $authMapper = new \Models\Auth\AuthMapper($this->db);
    $userMapper = new \Models\User\UserMapper($this->db);
    $session = new \Models\Session\Session;
    $sessionMapper = new \Models\Session\SessionMapper($this->db);

    $email_hash = $security->simpleHash($email);

    if (!$auth = $authMapper->fetchWhere('email_hash', $email_hash))
    {
        echo 'User doesnt exist'; 
        return;
    }

    if (!$auth->verifyPassword($password))
    {
        echo 'Password not correct'; 
        return;
    }

    $user = $userMapper->fetchById($auth->user_id);

    $session->createUserSession($user);

    $sessionMapper->save($session);
}

这里有一些担忧。首先是缺乏依赖注入。第二个是这是一个繁琐的代码块,用于使用我可能想要提供登录功能的每个地方。

那么这个逻辑应该在哪里?在控制器中?在用户域对象中?在 Auth 域对象中?这似乎是一种循环 - 数据映射器的全部意义在于,域对象甚至不处理自身的持久性,更不用说其他对象了....应该将其放置在用户或身份验证服务层中/User/ 或 /Auth/ 模型?

对于这类事情的最佳实践,我有点迷茫。

另外请记住,我这样做是出于学习目的,所以我不想只使用 Symfony 之类的东西。

4

2 回答 2

0

为了回答我自己的问题,我决定最好的地方是创建一个AccountController接受LoginHandlerInterface接口作为构造函数参数的接口。

AccountController 然后看起来像这样:

namespace App\Controllers;

class AccountController
{
    protected $LoginHandler;

    public function __construct(\Framework\Interfaces\LoginHandlerInterface $LoginHandler)
    {
        $this->LoginHandler = $LoginHandler;
    }

    public function login()
    {
        if (/* ...  form validation stuff ... */)
        {
            try 
            {
                $this->LoginHandler->login($email, $password);
            }
            catch (\Framework\Exceptions\Login $e) 
            {
                // Assign login errors to template etc...
            } 
        }
    }
}

然后无论LoginHandler我最终使用哪个,都拥有完成所有登录所需的一切(查找用户、验证密码、更新会话等)。这使我保持AccountController清洁、灵活和可测试。

我通过自动解析构造函数依赖关系的 IoC 容器中的配置注入所需的LoginHandler(和RegistrationHandler,我没有在这里显示)。

于 2013-12-31T01:45:26.130 回答
-1

Auth 应该在登录失败时处理登录,如果失败则返回 false,如果为 true,则执行会话的逻辑并返回 true。

因此,在您的控制器中,您将执行类似 if(Auth->login($email,$password)) 的操作

ps:对于这种类型的工作流程,我更喜欢使用单例模式(它会破坏单元测试),但我认为它更适合你。

于 2013-12-26T13:46:17.990 回答