Я пытаюсь внедрить пользовательскую систему аутентификации для своего приложения.
Для этого я создал класс (lib) с именем Auth, который расширяет мой UserRepository, поэтому я могу использовать модель непосредственно в своем классе аутентификации.
<?php
namespace App\Lib;
use App\Repository\UserRepository;
class Auth extends UserRepository {
Внутри моей функции аутентификации, которая находится в Auth, я вызываю функцию findByCredentials, которая должна вернуть мне некоторые пользовательские данные из базы данных.
$user = $this->findByCredentials($email, $password);
Я вызываю это внутри своего контроллера, чтобы заставить его работать
public function index(Request $request) {
$auth = new Auth();
$auth->authenticate(null, '[email protected]', '1234');
return $this->tpl();
}
Это мой UserRepository, который был сгенерирован автоматически, и я добавил только эту функцию.
<?php
namespace App\Repository;
use App\Entity\User;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Symfony\Bridge\Doctrine\RegistryInterface;
class UserRepository extends ServiceEntityRepository
{
public function __construct(RegistryInterface $registry)
{
parent::__construct($registry, User::class);
}
public function findByCredentials($email, $password)
{
return $this->createQueryBuilder('user')
->andWhere('user.email = :email')
->andWhere('user.password = :password')
->setParameters([
'email' => $email,
'password' => $password
])
->getQuery()
->getResult();
}
Но тогда я получаю ошибку, упомянутую в заголовке.
Я использовал cli/console для генерации всего и убедился, что моя таблица существует в базе данных. Я использую MySQL v5.7 на Linux-машине.
Я также настроил config/packages/doctrine.yaml
Конструктор класса авторизации
public function __construct($jwt = null, $email = null, $password = null) {
$this->jwt = $jwt;
$this->email = $email;
$this->password = $password;
}
@Jakumi Я обновил вопрос, как вы просили. Вы имеете в виду, что конструктор класса Auth должен иметь эту зависимость?
Проблема в том, что вы создаете экземпляр Auth самостоятельно, а не через методы DependencyInjection. Если вы внимательно посмотрите, то заметите, что new Auth() не получает никаких аргументов, необходимых __construct() в вашем классе UserRepository. Следуйте рекомендациям и немного реорганизуйте свой код, и все будет хорошо.
@Artamiel Привет, спасибо за ответ. Не могли бы вы предоставить мне некоторые ресурсы, где я могу прочитать больше об этом материале. Я попытался внедрить RegistryInterface и вызвать parent::__construct() внутри моего конструктора класса Auth, но он говорит: «Невозможно создать экземпляр интерфейса». Единственное, чего я действительно пытаюсь добиться, - это иметь небольшую библиотеку, которая имеет некоторую логику и может выполнять некоторые простые запросы sql и в то же время не быть контроллером.






Вы, по-видимому, удаляете преимущества внедрения зависимостей.
внедрение зависимостей, по сути, заключается в том, что вы не создаете службу внутри своего класса, а вместо этого предоставляете ее в качестве параметра либо в конструкторе, либо в вызовах функций. (В фреймворке symfony вам обычно не нужно создавать его в другом месте, но symfony позаботится о том, чтобы предоставить его вам, если только вы явно не хотите вызывать функцию/конструктор... вот почему вы обычно не т.)
Одним из примеров может быть контроллер, где Request $request (подсказка типа) предоставляется фреймворком. Технически у вас может быть почти любой класс с подсказкой типа, если фреймворк (точнее, контейнер) знает этот класс и как сгенерировать его/экземпляр. То, что контейнер генерирует для вас зависимости, подключается к автопроводке или автоконфигурации, и это очень-очень удобно. (Документы для Symfony: https://symfony.com/doc/current/service_container.html)
В вашем конкретном примере: я бы посоветовал не расширять UserRepository и предложить две лучшие альтернативы:
UserRepositoryесли вы хотите расширить UserRepository, и этот UserRepository уже специфичен и несколько уникален для вашего проекта, почему бы не поместить «расширение» прямо в UserRepository? Я действительно не могу придумать очень веской причины, чтобы не делать этого. Однако ...
Auth.Поскольку в создание репозитория на стороне доктрины входит некоторая серьезная подготовка, и в нем задействованы некоторые одноэлементные зависимости (реестр, соединение, ...) и где-то закопанные, пойдите по пути автоматического подключения/автоматической настройки framework и сделайте UserRepository параметром вашего Auth сервиса:
class Auth {
/** @var UserRepository */
private $userRepository;
public function __construct(UserRepository $userRepository) {
$this->userRepository = $userRepository;
}
public function authenticate(...) {
/* some logic that can use $this->userRepository */
}
}
Важное замечание: у вас есть jwt, электронная почта, пароль в качестве параметров вашего Auth. Это имеет семантическое различие: либо это Сервис, который аутентифицирует пользователей, и в этом случае jwt, электронная почта и пароль точно не должны быть частью конструктора, потому что тогда это будет аутентификация для ОДНОГО пользователя, для которого он создан ... что почти не приносит пользы. В противном случае он должен получить эти параметры при вызове аутентификации, что, на мой взгляд, имеет больше смысла.
Однако, ЕСЛИ вы используете какой-то сложный протокол аутентификации, когда вы взаимодействуете с внешним сервером, которому требуются некоторые дополнительные учетные данные ПОВЕРХ учетных данных пользователя (авторизация пользователя как служба или что-то еще), тогда мой аргумент недействителен, и вы должны научиться определять Учетные данные аутентификации в services.yaml.
Но я подозреваю, что это не так. Вероятно, стоит на мгновение подумать о состоянии. В общем, узнайте, что на самом деле необходимо для построения сервиса, и эти вещи добавьте в конструктор. Когда служба должна что-то СДЕЛАТЬ, это относится к параметрам методов службы.
Создавать Auth самостоятельно довольно неудобно, потому что вам пришлось бы переделывать многие функции, которые уже предоставляет внедрение зависимостей symfony + автосвязывание + автонастройка. Чистый способ - ввести то, что вам нужно.
Я повторю ваш индексный маршрут здесь и добавлю комментарий ниже
public function index(Request $request) {
$auth = new Auth();
$auth->authenticate(null, '[email protected]', '1234');
return $this->tpl();
}
хотя это и не является строго обязательным, обычно функции маршрута контроллера называют [something]Action, поэтому indexAction. Во-вторых, вы, видимо, не используете Request, поэтому вам следует удалить его. В-третьих, добавьте либо UserRepository, либо Auth в заголовок вашего метода (в зависимости от того, какой вариант вы выбрали):
// this goes into your controller
// or: public function indexAction(UserRepository $userRepository) {
public function indexAction(Auth $auth) {
$auth->authenticate(/** ... your parameters ... */);
return $this->tpl(); // <-- what's this? ;o)
}
Я подозреваю, что у вас есть
__constructв вашемAuthклассе? пожалуйста, покажите это. Но я подозреваю, что вы нарушаете используемую инъекцию зависимостей. Почему бы вам просто не добавить функции в Auth к вашемуUserRepository? В вашем контроллере вам, вероятно, следует добавить UserRepository в список параметров функции, чтобы он правильно вводился. (Пожалуйста, также покажите заголовок функции/маршрута вашего контроллера)