我在 Symfony 2.2.1 上有一个简单的登录系统,问题是何时进入安全区域是的,显示登录表单并输入用户并通过,但总是将我发送到/login
页面,有时将我发送到/
. 查看日志我得到以下信息
[2013-04-22 20:25:01] event.DEBUG: Notified event "kernel.request" to listener "Symfony\Component\HttpKernel\EventListener\ProfilerListener::onKernelRequest". [] []
[2013-04-22 20:25:01] event.DEBUG: Notified event "kernel.request" to listener "Symfony\Bundle\FrameworkBundle\EventListener\SessionListener::onKernelRequest". [] []
[2013-04-22 20:25:02] event.DEBUG: Notified event "kernel.request" to listener "Symfony\Component\HttpKernel\EventListener\FragmentListener::onKernelRequest". [] []
[2013-04-22 20:25:02] event.DEBUG: Notified event "kernel.request" to listener "Symfony\Component\HttpKernel\EventListener\RouterListener::onKernelRequest". [] []
[2013-04-22 20:25:02] request.INFO: Matched route "login_check" (parameters: "_route": "login_check") [] []
[2013-04-22 20:25:02] event.DEBUG: Notified event "kernel.request" to listener "Symfony\Component\HttpKernel\EventListener\LocaleListener::onKernelRequest". [] []
[2013-04-22 20:25:02] event.DEBUG: Notified event "kernel.request" to listener "Symfony\Component\Security\Http\Firewall::onKernelRequest". [] []
[2013-04-22 20:25:02] doctrine.DEBUG: SELECT t0.id AS id1, t0.nombre AS nombre2, t0.contrasena AS contrasena3, t0.salt AS salt4 FROM usuario t0 WHERE t0.nombre = ? LIMIT 1 ["rkmax"] []
[2013-04-22 20:25:02] doctrine.DEBUG: SELECT t0.id AS id1, t0.nombre AS nombre2 FROM rol t0 INNER JOIN usuario_rol ON t0.id = usuario_rol.rol_id WHERE usuario_rol.usuario_id = ? [8] []
[2013-04-22 20:25:02] security.INFO: User "" has been authenticated successfully [] []
...
[2013-04-22 20:25:02] security.WARNING: Username "" could not be found. [] []
如您所见,在 SecurityContext 中写入时用户为空,但我不知道原因。
课程和设置
class SecurityController extends Controller
{
public function loginAction()
{
$request = $this->getRequest();
$session = $request->getSession();
if ($request->attributes->has(SecurityContext::AUTHENTICATION_ERROR)) {
$error = $request->attributes->get(SecurityContext::AUTHENTICATION_ERROR);
} else {
$error = $session->get(SecurityContext::AUTHENTICATION_ERROR);
$session->remove(SecurityContext::AUTHENTICATION_ERROR);
}
return $this->render('MySecurityBundle:Security:login.html.twig', array(
'last_username' => $session->get(SecurityContext::LAST_USERNAME),
'error' => $error,
));
}
}
两个实体Usuario
(用户)和Rol
(角色)都实现了与 symfony 安全对话的接口
class Rol implements RoleInterface
//Repository/Usuario
class Usuario extends EntityRepository implements UserProviderInterface
{
public function loadUserByUsername($login)
{
$usuario = $this->findOneBy(array('nombre' => $login));
if (!$usuario) {
throw new UsernameNotFoundException(
sprintf("El usuario '%s' no existe o el nombre esta mal escrito", $login)
);
}
return $usuario;
}
public function refreshUser(UserInterface $usuario)
{
return $this->loadUserByUsername($usuario);
}
public function supportsClass($class)
{
return $class === 'Iscltda\SecurityBundle\Entity\Usuario';
}
}
class Usuario implements UserInterface, \Serializable
{
/**
* @var integer
*
* @ORM\Column(name="id", type="integer", nullable=false)
* @ORM\Id
* @ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* @var string
*
* @ORM\Column(name="nombre", type="string", length=200, nullable=false)
*/
private $nombre;
/**
* @var string
*
* @ORM\Column(name="contrasena", type="string", length=64, nullable=false)
*/
private $contrasena;
/**
* @var string
*
* @ORM\Column(name="salt", type="string", length=64, nullable=false)
*/
private $salt;
/**
* @var \Doctrine\Common\Collections\Collection
*
* @ORM\ManyToMany(targetEntity="Rol", inversedBy="usuario")
* @ORM\JoinTable(name="usuario_rol",
* joinColumns={
* @ORM\JoinColumn(name="usuario_id", referencedColumnName="id")
* },
* inverseJoinColumns={
* @ORM\JoinColumn(name="rol_id", referencedColumnName="id")
* }
* )
*/
private $rol;
/**
* Constructor
*/
public function __construct()
{
$this->rol = new \Doctrine\Common\Collections\ArrayCollection();
}
public function __toString()
{
return $this->getNombre();
}
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set nombre
*
* @param string $nombre
* @return Usuario
*/
public function setNombre($nombre)
{
$this->nombre = $nombre;
return $this;
}
/**
* Get nombre
*
* @return string
*/
public function getNombre()
{
return $this->nombre;
}
/**
* Set contrasena
*
* @param string $contrasena
* @return Usuario
*/
public function setContrasena($contrasena)
{
$this->contrasena = $contrasena;
return $this;
}
/**
* Get contrasena
*
* @return string
*/
public function getContrasena()
{
return $this->contrasena;
}
/**
* Set salt
*
* @param string $salt
* @return Usuario
*/
public function setSalt($salt)
{
$this->salt = $salt;
return $this;
}
/**
* Get salt
*
* @return string
*/
public function getSalt()
{
return $this->salt;
}
/**
* Add rol
*
* @param \Iscltda\SecurityBundle\Entity\Rol $rol
* @return Usuario
*/
public function addRol(\Iscltda\SecurityBundle\Entity\Rol $rol)
{
$this->rol[] = $rol;
return $this;
}
/**
* Remove rol
*
* @param \Iscltda\SecurityBundle\Entity\Rol $rol
*/
public function removeRol(\Iscltda\SecurityBundle\Entity\Rol $rol)
{
$this->rol->removeElement($rol);
}
/**
* Get rol
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getRol()
{
return $this->rol;
}
public function getRoles()
{
return $this->rol->toArray();
}
public function getPassword()
{
return $this->getContrasena();
}
public function getUsername()
{
$this->getNombre();
}
public function eraseCredentials()
{
}
/**
* Serializes the content of the current User object
* @return string
*/
public function serialize()
{
return \serialize(array(
$this->id,
$this->nombre,
$this->salt,
$this->contrasena
));
}
/**
* Unserializes the given string in the current User object
* @param serialized
*/
public function unserialize($serialized)
{
list(
$this->id,
$this->nombre,
$this->salt,
$this->contrasena
) = \unserialize($serialized);
}
}
routing.yml
设置_
login:
pattern: /admin/login
defaults: { _controller: MySecurityBundle:Security:login }
login_check:
pattern: /admin/login_check
logout:
pattern: /admin/logout
这是我的security.yml
设置
security:
encoders:
MyVendor\MySecurityBundle\Entity\Usuario:
algorithm: sha256
encode-as-base64: true
iterations: 10
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
providers:
user_db:
entity: { class: MyVendor\MySecurityBundle\Entity\Usuario, property: nombre }
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
login:
pattern: ^/admin/login$
security: false
anonymous: ~
secured_area:
provider: user_db
security: true
pattern: ^/admin
form_login:
login_path: /admin/login
check_path: /admin/login_check
logout:
path: /logout
target: /
更新
我发现问题是我getUsername
更改为的方法中没有返回任何内容
public function getUsername()
{
return $this->getNombre();
}
但仍然将我发送到登录页面
更新 2
我在 UserProvider 类中发现了最后一个问题,该方法refreshUser
是错误的,我已更改为
public function refreshUser(UserInterface $usuario)
{
return $this->loadUserByUsername($usuario->getUsername());
}
这可以正常工作