尽我所能遵循Symfony文档。我已经尝试过所有形式的编码算法,而后卫界面根本不想记录任何用户。有人看到我在做错了吗?
这里是所有代码
控制器的登录部分:
namespace AppBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\User\UserInterface;
class SecurityController extends Controller
{
/**
* @param $name
* @return \Symfony\Component\HttpFoundation\Response
* @Route("/login", name="login")
*/
public function indexAction(Request $request)
{
$user = $this->getUser();
if($user instanceof UserInterface) {
return $this->redirectToRoute('homepage');
}
return $this->render('AppBundle:Security:index.html.twig', array(
'error' => $this->get('security.authentication_utils')->getLastAuthenticationError(),
'last_username' => $this->get('security.authentication_utils')->getLastUsername()
));
}
}
security.yml
security:
providers:
in_memory:
memory: ~
encoders:
AppBundle\Entity\User: sha512
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
anonymous: ~
logout:
path: /logout
target: /
guard:
authenticators:
- form_authenticator
entry_point: form_authenticator
access_control:
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
Doctrine用户实体:
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Class User
* @package AppBundle\Entity
* @ORM\Entity(repositoryClass="AppBundle\Entity\UserRepository")
* @ORM\Table(name="users")
*/
class User implements UserInterface, \Serializable {
/**
* @ORM\Column(type="string")
* @ORM\Id
* @ORM\GeneratedValue(strategy="UUID")
*/
private $id;
/**
* @ORM\Column(type="string", length=100)
*/
private $username;
/**
* @ORM\Column(type="string", length=100)
*/
private $email;
/**
* @ORM\Column(type="string", length=255)
*/
private $password;
/**
* @Assert\NotBlank()
* @Assert\Length(max=4096)
*/
private $plainPassword;
/**
* Get id
*
* @return string
*/
public function getId()
{
return $this->id;
}
/**
* Set username
*
* @param string $username
*
* @return User
*/
public function setUsername($username)
{
$this->username = $username;
return $this;
}
/**
* Get username
*
* @return string
*/
public function getUsername()
{
return $this->username;
}
/**
* Set email
*
* @param string $email
*
* @return User
*/
public function setEmail($email)
{
$this->email = $email;
return $this;
}
/**
* Get email
*
* @return string
*/
public function getEmail()
{
return $this->email;
}
/**
* Set password
*
* @param string $password
*
* @return User
*/
public function setPassword($password)
{
$this->password = $password;
return $this;
}
/**
* Get password
*
* @return string
*/
public function getPassword()
{
return $this->password;
}
/**
* String representation of object
* @link http://php.net/manual/en/serializable.serialize.php
* @return string the string representation of the object or null
* @since 5.1.0
*/
public function serialize()
{
return serialize(array(
$this->getId(),
$this->getUsername(),
$this->getEmail(),
$this->getPassword()
));
}
/**
* Constructs the object
* @link http://php.net/manual/en/serializable.unserialize.php
* @param string $serialized <p>
* The string representation of the object.
* </p>
* @return void
* @since 5.1.0
*/
public function unserialize($serialized)
{
$id = $this->getId();
$username = $this->getUsername();
$email = $this->getEmail();
$password = $this->getPassword();
list(
$id,
$username,
$email,
$password
) = unserialize($serialized);
}
/**
* Returns the roles granted to the user.
*
* <code>
* public function getRoles()
* {
* return array('ROLE_USER');
* }
* </code>
*
* Alternatively, the roles might be stored on a ``roles`` property,
* and populated in any number of different ways when the user object
* is created.
*
* @return (Role|string)[] The user roles
*/
public function getRoles()
{
return array(
'ROLE_USER'
);
}
/**
* Returns the salt that was originally used to encode the password.
*
* This can return null if the password was not encoded using a salt.
*
* @return string|null The salt
*/
public function getSalt()
{
return null;
}
/**
* Removes sensitive data from the user.
*
* This is important if, at any given point, sensitive information like
* the plain-text password is stored on this object.
*/
public function eraseCredentials()
{
}
/**
* @return string
*/
public function getPlainPassword()
{
return $this->plainPassword;
}
/**
* @param string $plainPassword
*/
public function setPlainPassword($plainPassword)
{
$this->plainPassword = $plainPassword;
}
}
用户实体的存储库:
namespace AppBundle\Entity;
use Symfony\Bridge\Doctrine\Security\User\UserLoaderInterface;
use Doctrine\ORM\EntityRepository;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Core\User\UserInterface;
class UserRepository extends EntityRepository implements UserLoaderInterface {
/**
* Loads the user for the given username.
*
* This method must return null if the user is not found.
*
* @param string $username The username
*
* @return UserInterface|null
*/
public function loadUserByUsername($username)
{
$user = $this->createQueryBuilder('u')
->where('u.username = :username')
->setParameter('username', $username)
->getQuery()
->getOneOrNullResult();
return $user;
}
}
登录表格树枝:
{% extends 'AppBundle::base.html.twig' %}
{% block mainContent %}
{% if error %}
<div>{{ error.messageKey|trans(error.messageData, 'security') }}</div>
{% endif %}
<form action="{{ path('login') }}" method="post">
<label for="username">Username/Email:</label>
<input type="text" id="username" name="username" value="{{ last_username }}">
<label for="password">Password:</label>
<input type="password" id="password" name="password">
<button type="submit">Login</button>
</form>
{% endblock %}
services.yml
parameters:
services:
form_authenticator:
class: AppBundle\Security\FormAuthenticator
arguments: ['@router', '@service_container']
......最后是authencator:
namespace AppBundle\Security;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Core\User\InMemoryUserProvider;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Guard\AbstractGuardAuthenticator;
class FormAuthenticator extends AbstractGuardAuthenticator {
/**
* @var RouterInterface
*/
private $router;
/**
* @var ContainerInterface
*/
private $container;
/**
* @var string
*/
private $failMessage = 'Chris says you are not valid.';
public function __construct(RouterInterface $routerInterface, ContainerInterface $containerInterface)
{
$this->container = $containerInterface;
$this->router = $routerInterface;
}
/**
* Returns a response that directs the user to authenticate.
*
* This is called when an anonymous request accesses a resource that
* requires authentication. The job of this method is to return some
* response that "helps" the user start into the authentication process.
*
* Examples:
* A) For a form login, you might redirect to the login page
* return new RedirectResponse('/login');
* B) For an API token authentication system, you return a 401 response
* return new Response('Auth header required', 401);
*
* @param Request $request The request that resulted in an AuthenticationException
* @param AuthenticationException $authException The exception that started the authentication process
*
* @return Response
*/
public function start(Request $request, AuthenticationException $authException = null)
{
$url = $this->router->generate('login');
return new RedirectResponse($url);
}
/**
* Get the authentication credentials from the request and return them
* as any type (e.g. an associate array). If you return null, authentication
* will be skipped.
*
* Whatever value you return here will be passed to getUser() and checkCredentials()
*
* For example, for a form login, you might:
*
* return array(
* 'username' => $request->request->get('_username'),
* 'password' => $request->request->get('_password'),
* );
*
* Or for an API token that's on a header, you might use:
*
* return array('api_key' => $request->headers->get('X-API-TOKEN'));
*
* @param Request $request
*
* @return mixed|null
*/
public function getCredentials(Request $request)
{
if($request->getPathInfo() != '/login' || !$request->isMethod('POST')) {
return;
}
return array(
'username' => $request->request->get('username'),
'password' => $request->request->get('password'),
);
}
/**
* Return a UserInterface object based on the credentials.
*
* The *credentials* are the return value from getCredentials()
*
* You may throw an AuthenticationException if you wish. If you return
* null, then a UsernameNotFoundException is thrown for you.
*
* @param mixed $credentials
* @param UserProviderInterface $userProvider
*
* @throws AuthenticationException
*
* @return UserInterface|null
*/
public function getUser($credentials, UserProviderInterface $userProvider)
{
if(!$userProvider instanceof InMemoryUserProvider) {
return;
}
dump($userProvider->loadUserByUsername($credentials['username'])); die();
try {
return $userProvider->loadUserByUsername($credentials['username']);
} catch(UsernameNotFoundException $e) {
throw new CustomUserMessageAuthenticationException($this->failMessage);
}
}
/**
* Returns true if the credentials are valid.
*
* If any value other than true is returned, authentication will
* fail. You may also throw an AuthenticationException if you wish
* to cause authentication to fail.
*
* The *credentials* are the return value from getCredentials()
*
* @param mixed $credentials
* @param UserInterface $user
*
* @return bool
*
* @throws AuthenticationException
*/
public function checkCredentials($credentials, UserInterface $user)
{
$plainPassword = $credentials['password'];
$encoder = $this->container->get('security.password_encoder');
if(!$encoder->isPasswordValid($user, $plainPassword)) {
throw new CustomUserMessageAuthenticationException($this->failMessage);
}
return true;
}
/**
* Called when authentication executed, but failed (e.g. wrong username password).
*
* This should return the Response sent back to the user, like a
* RedirectResponse to the login page or a 403 response.
*
* If you return null, the request will continue, but the user will
* not be authenticated. This is probably not what you want to do.
*
* @param Request $request
* @param AuthenticationException $exception
*
* @return Response|null
*/
public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
{
$request->getSession()->set(Security::AUTHENTICATION_ERROR, $exception);
$url = $this->router->generate('login');
return new RedirectResponse($url);
}
/**
* Called when authentication executed and was successful!
*
* This should return the Response sent back to the user, like a
* RedirectResponse to the last page they visited.
*
* If you return null, the current request will continue, and the user
* will be authenticated. This makes sense, for example, with an API.
*
* @param Request $request
* @param TokenInterface $token
* @param string $providerKey The provider (i.e. firewall) key
*
* @return Response|null
*/
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
$url = $this->router->generate('homepage');
return new RedirectResponse($url);
}
/**
* Does this method support remember me cookies?
*
* Remember me cookie will be set if *all* of the following are met:
* A) This method returns true
* B) The remember_me key under your firewall is configured
* C) The "remember me" functionality is activated. This is usually
* done by having a _remember_me checkbox in your form, but
* can be configured by the "always_remember_me" and "remember_me_parameter"
* parameters under the "remember_me" firewall key
*
* @return bool
*/
public function supportsRememberMe()
{
return false;
}
}