I was looking to create a service provider in order to logIn with Email and not username with FOSUserBundle.
First I wrote this in my security.yml
file according to the doc here:
security:
providers:
fos_userbundle:
id: fos_user.user_provider.username_email
According to the FOS doc, I follow these steps one by one.
Except in MyUserManager.php I wrote this (according to another question on stack here):
namespace Frontend\UserBundle\Model;
use FOS\UserBundle\Entity\UserManager;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
class CustomUserManager extends UserManager
{
public function loadUserByUsername($email)
{
/*$user = $this->findUserByUsernameOrEmail($username);
if (!$user) {
throw new UsernameNotFoundException(sprintf('No user with name "%s" was found.', $username));
}
return $user;*/
//Change it to only email (Default calls loadUserByUsername -> we send it to our own loadUserByEmail)
return $this->loadUserByEmail($email);
}
public function loadUserByEmail($email)
{
$user = $this->findUserByEmail($email);
if (!$user) {
throw new UsernameNotFoundException(sprintf('No user with email "%s" was found.', $email));
}
return $user;
}
}
and of course I changed the User class in order to implement specific getter and setter like this:
namespace Acme\UserBundle\Entity;
use FOS\UserBundle\Entity\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(repositoryClass="Acme\UserBundle\Entity\UserRepository")
* @ORM\Table(name="users")
*/
class User extends BaseUser
{
// ...
// override methods for username and tie them with email field
/**
* Sets the email.
*
* @param string $email
* @return User
*/
public function setEmail($email)
{
$this->setUsername($email);
return parent::setEmail($email);
}
/**
* Set the canonical email.
*
* @param string $emailCanonical
* @return User
*/
public function setEmailCanonical($emailCanonical)
{
$this->setUsernameCanonical($emailCanonical);
return parent::setEmailCanonical($emailCanonical);
}
// ...
}
But I owerride the FOSUser template form in app\Resources\FOSUserBundle\views\Security\login.html.twig
like this:
{% block fos_user_content %}
<form action="{{ path("fos_user_security_check") }}" method="post">
<input type="hidden" name="_csrf_token" value="{{ csrf_token }}"/>
<label class="" for="username">E-mail</label>
<input type="email" class="" id="username" name="_username" required="required"/>
<label class="" for="password">{{ 'security.login.password'|trans }}</label>
<input class="" type="password" id="password" name="_password" required="required"/>
<label class="" for="remember_me">
<input type="checkbox" id="remember_me" name="_remember_me" class="">
<span class="">{{ 'security.login.remember_me'|trans }}</span>
</label>
<button class="" type="submit" id="_submit" name="_submit" value="{{ 'security.login.submit'|trans }}">
LogIn
</button>
</form>
{% endblock fos_user_content %}
It is the good way to only allow user Loged In with email field and not the username?
Your approach resumes perfectly all mandatory changes for setup an email-password authentication on FOSUserBundle.
For now, I used only the same configuration in entity and security config (not need of the template because my login is done in AJAX). The only doubt I have is the following :
As the username
is always set using the email
field value, is it useful to create your CustomUserManager ?
The loadByUsername will works if the username is always equal to the email, as done by your entity in setEmail
and setEmailCanonical
.
Is it just an additional security ?
EDIT
Change from username to email can involves to change some comportment in form building/validation.
Maybe you have to look at this answer : https://stackoverflow.com/a/21064627/4363634
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With