我正试图用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
当我提供正确的凭据时,大约20%的时间我会正确登录/重定向到给定的URL。其他80%的时间我只是被重定向回表单登录页面,没有错误消息。当我尝试使用不正确的凭据登录时,我也没有看到任何错误消息。
更新:问题似乎是Symfony在我的数据库中为每个请求创建了多个会话。我正在使用pdo处理程序。
去掉你的login_firewall
,这是不需要的,因为你有一个允许匿名访问登录页面的access_control规则。防火墙越少越好。
我怀疑,当你无法登录时,你是在直接访问你的登录页面(/login),因此,试图在你的"login_firewall"下登录,这是无用的,因为这只对/login页面有好处。在login_firewall下登录后,您将被重定向到/
,但您没有在"secured_area"防火墙(保护/
)下进行身份验证,因此它要求您再次登录,但这次是在正确的防火墙下。我想这一次你可以登录了。
这可能是问题所在,但无论如何,请删除您的login_firewall
事实证明,问题实际上与我存储会话的Session
实体/表有关。我使用PDOSessionHandler将会话存储在数据库中,并且在我的ORM Session
实体中有以下$id
:
<?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
,一切似乎都正常工作。