在我当前的应用中,我们选择不使用Doctrine或ORM。我正在尝试使用Symfony 4.1的身份验证系统登录用户。我想做的是直接使用PDO从数据库中获取用户。
我正在遵循本指南:http://symfony.com/doc/current/security/custom_provider.html。在security.yaml
中,我创建了一个新的provider
条目并将其添加到防火墙:
providers:
db_provider:
id: App\Utility\Security\UserAuthenticationProvider
encoders:
App\Utility\Security\UserAuthenticationProvider: bcrypt
firewalls:
main:
pattern: ^/
form_login:
login_path: login
check_path: check_login
default_target_path: user
anonymous: ~
provider: db_provider
我已经创建了UserAuthenticationProvider
:
class UserAuthenticationProvider implements UserProviderInterface {
private $config;
private $userDAO;
public function __construct() {
$this->config = new Config();
$this->userDAO = new MySqlUserDAO($this->config);
}
public function loadUserByUsername($username) {
$user = $this->userDAO->getUserByUsername();
...
return $user;
}
public function refreshUser(UserInterface $user) {
...
}
public function supportsClass($class) {
...
}
我的userDAO
返回一个实现UserInterface
的对象。
因此,当我到达/login
路线时,我得到了登录表格。但是,没有从数据库加载用户。我可以看到我的UserProviderInterface已创建(通过在构造函数中使用dump
来创建,但是loadUserByUsername
却没有。
我是否需要实现其他使用我的UserAuthenticationProvider
并调用loadUserByUsername
的东西?
也许不使用Doctrine就可以在Symfony中进行身份验证吗?
更新
我发现this guide较旧,但具有更多的细节/上下文。
我已经这样更改了我的类/配置(为简洁起见进行了编辑):
#security.yaml
security:
providers:
db_provider:
id: database_user_provider
main:
pattern: ^/
form_login:
provider: db_provider
login_path: login
check_path: check_login
default_target_path: do_some_stuff
。
#services.yaml
services:
database_user_provider:
class: App\Utility\Security\DatabaseUserProvider
。
class DatabaseUser
implements
UserInterface,
EquatableInterface
{
protected $user;
public function getUser(): User {
return $this->user;
}
public function setUser(User $user): void {
$this->user = $user;
}
public function getRoles() {
return array("ROLE_USER");
}
public function getPassword() {
return $this->getUser()->getPassword();
}
public function getUsername() {
return $this->getUser()->getUsername();
}
}
。
class DatabaseUserProvider implements UserProviderInterface {
private $config;
private $userDAO;
public function __construct() {
$this->config = new Config();
$this->userDAO = new MySqlUserDAO($this->config);
}
public function loadUserByUsername($username): UserInterface {
$user = $this->userDAO->getUserByUsername($username);
$dbUser = new DatabaseUser();
$dbUser->setUser($user);
return $dbUser;
}
public function refreshUser(UserInterface $user) {
return $this->loadUserByUsername($user->getUsername());
}
public function supportsClass($class) {
return DatabaseUser::class === $class;
}
}
所以每个文件在做什么(简而言之):
services.yaml:将我的类DatabaseUserProvider
命名为服务名称database_user_provider
,以便在security.yaml中使用。
security.yaml:将database_user_provider
设置为别名db_provider
,并将其添加为main
防火墙上的提供者。
DatabaseUser:我的“实体”类,代表数据库中的用户。我有一个愚蠢的User
类,它只有几个属性(用户名,密码)和这些属性的getters / setter方法。设置为DatabaseUser
对象的属性。
DatabaseUserProvider:使用DAO从数据库加载我的DatabaseUser对象并返回它们。 (更具体地说,DAO返回一个用户,该用户被添加到一个新的DatabaseUser对象中,该对象又被返回)。
DAO只需运行sql查询即可从用户表中获取单个结果。然后它将获取此结果并填充一个User
值对象并返回它。
结果
当我使用Doctrine时(并遵循本指南的loading users from the database和this one for a login form),SecurityController
上的登录路径将同时处理表单的呈现和登录请求的处理。不知何故,Symfony / Doctrine非常聪明,可以自动(使用侦听器?)从数据库中加载适当的用户实体,并根据他们提供的密码对它们进行身份验证(然后设置用户令牌并将其重定向到他们所在的页面)尝试访问。)
当我绕过理论(并使用我自己的DAO)和上面的类时,身份验证仍然不会发生。我可以看到正在创建DatabaseUserProvider
的实例(通过在构造函数中转储一些var),并且配置文件的“安全性”选项卡显示database_user_provider
为提供者。但这似乎已经达到了极限。
问题
在我看来DatabaseUserProvider::loadUserByUsername
应该是接下来要发生的事情。从何处调用此方法?我需要将用户名传递到构造函数中并从那里开始吗?我是否应该在控制器中将该类用作服务并从控制器中手动调用该方法(使用原则时我不必做的事-控制器中没有此逻辑)?