Я пытаюсь реализовать довольно базовую форму входа с Symfony2.3, но у меня возникает ошибка, когда я иногда перенаправляюсь на ожидаемую страницу после предоставления правильных учетных данных, но иногда нет (вместо этого я просто перенаправлен обратно на страницу входа в систему). Вот мой файл security.yml
:
security:
encoders:
Symfony\Component\Security\Core\User\User: plaintext
Acme\MyBundle\Entity\User: sha512
providers:
main:
id: acme.user.provider
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
login_firewall:
pattern: ^/login$
security: false
secured_area:
pattern: ^/
form_login: ~
logout:
path: /logout
target: /
access_control:
- { path: ^/login$, roles: IS_AUTHENTICATED_ANONYMOUSLY, requires_channel: https }
- { path: ^/, roles: ROLE_USER, requires_channel: https }
Вот мой SecurityController
:
<?php
namespace Acme\MyBundle\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\SecurityContextInterface;
/**
* Class SecurityController
* @package Acme\MyBundle\Controller
*
* @Route("/")
*/
class SecurityController extends Controller
{
/**
* @param Request $request
* @return \Symfony\Component\HttpFoundation\Response
*
* @Route("/login", requirements={"_scheme" = "https"}, path="login")
*/
public function LoginAction(Request $request)
{
$session = $request->getSession();
// get the login error if there is one
if ($request->attributes->has(SecurityContextInterface::AUTHENTICATION_ERROR)) {
$error = $request->attributes->get(
SecurityContextInterface::AUTHENTICATION_ERROR
);
} elseif (null !== $session && $session->has(SecurityContextInterface::AUTHENTICATION_ERROR)) {
$error = $session->get(SecurityContextInterface::AUTHENTICATION_ERROR);
$session->remove(SecurityContextInterface::AUTHENTICATION_ERROR);
} else {
$error = '';
}
// last username entered by the user
$lastUsername = (null === $session) ? '' : $session->get(SecurityContextInterface::LAST_USERNAME);
return $this->render(
'AcmeMyBundle:Security:login.html.twig',
array(
// last username entered by the user
'last_username' => $lastUsername,
'error' => $error,
)
);
}
/**
* @Route("/login_check", requirements={"_scheme" = "https"}, path="login_check")
*/
public function LoginCheckAction()
{
}
/**
* @Route("/logout", requirements={"_scheme" = "https"}, path="logout")
*/
public function LogoutAction()
{
}
}
И вот мой файл routing.yml
:
_security:
resource: "@AcmeMyBundle/Controller/SecurityController.php"
type: annotation
Когда я предоставляю правильные учетные данные, я правильно зарегистрирован/перенаправлен на указанный URL примерно в 20% случаев. Другие 80% времени я просто перенаправлен обратно на страницу входа в форму без сообщения об ошибке. Я также не вижу сообщения об ошибке при попытке входа в систему с неправильными учетными данными.
ОБНОВЛЕНИЕ. Похоже, проблема заключается в том, что Symfony создает несколько сеансов в моей базе данных по каждому запросу. Я использую обработчик pdo.
Оказывается, проблема связана с сущностью/таблицей Session
в которой я сохранял сеанс. Я использовал PDOSessionHandler для хранения сеансов в базе данных и имел следующий $id
в моем объекте Session
ORM:
<?php
namespace Acme\MyBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Session
*
* @ORM\Table()
* @ORM\Entity
*/
class Session
{
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
$id
не должен был иметь тип integer, но (очевидно (-_-) строки типа. После изменения свойства:
/**
* @var integer
*
* @ORM\Column(type="string", length=255)
* @ORM\Id
*/
private $id;
и запуск php app/console doctrine:schema:update --force
, все работает правильно.
избавиться от вашего login_firewall
, он не нужен, поскольку у вас есть правило access_control, которое позволяет анонимный доступ к вашей странице входа. Чем меньше брандмауэров у вас, тем лучше.
Я подозреваю, что раз, когда вы не можете войти в систему, вы непосредственно посещаете страницу входа в систему (/login) и, следовательно, пытаетесь войти в систему под своим "login_firewall", что бесполезно, потому что это полезно только для страницы /login. После того, как вы входите под свой login_firewall, вы перенаправлены в /
, но вы не авторизованы под своим защищенным брандмауэром secure_area (который защищает /
), поэтому он просит вас снова войти в систему, но на этот раз под правильным брандмауэром. Я бы предположил, что на этот раз вы сможете войти.
Это может быть проблемой, но независимо от того, избавиться от вашего login_firewall
anonymous: ~
в secured_area исправила проблему перенаправления, но не проблему цикла входа в систему.