我们的目的是让用户可以使用用户名或者email登录。如果我们能够让Security系统使用我们闪亮牛逼的findOneByUsernameOrEmail方法查找用户并登录,那么今天的任务就完成了。
打开security.yml并移除providers键下的属性,重新填写他们:
1 2 3 4 5 6 7 |
# app/config/security.yml security: # ... providers: our_database_users: entity: { class: UserBundle:User } |
现在试试,天呀!报了一个错误:
> The Doctrine repository “YodaUserBundleEntityUserRepository” must implement UserProviderInterface.
UserProviderInterface
没有这些属性,doctrine不知道如何查找用户。相反,它试图调用我们UserRepository中的一个方法。但对于这个工作,我们的UserRepository类必须实现UserProviderInterface。
因此,让我们打开UserRepository
1 2 3 4 5 6 7 8 9 |
// src/Yoda/UserBundle/Entity/UserRepository.php // ... use Symfony\Component\Security\Core\User\UserProviderInterface; class UserRepository extends EntityRepository implements UserProviderInterface { // ... } |
和往常一样不要忘记使用use声明!这个接口提供了三个方法:refreshUser, supportsClass andloadUserByUsername. 我都粘贴进来:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
// src/Yoda/UserBundle/Entity/UserRepository.php // ... use Symfony\Component\Security\Core\User\UserProviderInterface; use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Core\Exception\UnsupportedUserException; use Symfony\Component\Security\Core\Exception\UsernameNotFoundException; class UserRepository extends EntityRepository implements UserProviderInterface { // ... public function loadUserByUsername($username) { // todo } public function refreshUser(UserInterface $user) { $class = get_class($user); if (!$this->supportsClass($class)) { throw new UnsupportedUserException(sprintf( 'Instances of "%s" are not supported.', $class )); } if (!$refreshedUser = $this->find($user->getId())) { throw new UsernameNotFoundException(sprintf('User with id %s not found', json_encode($user->getId()))); } return $refreshedUser; } public function supportsClass($class) { return $this->getEntityName() === $class || is_subclass_of($class, $this->getEntityName()); } } |
填充loadUserByUsername
这个loadUserByUsername方法很重要,因为当你使用User对象的username登录时,symfony就会调用他。所以在这里我们可以使用任何逻辑,例如 可以返回用户名“Jar Jar Binks”:
1 2 3 4 5 6 7 |
public function loadUserByUsername($username) { if ($username == 'jarjarbinks') { // nope! return; } } |
我们在这里可以使用我们之前创建的findOneByUsernameOrEmail方法。如果没有发现用户,我们抛出一个UsernameNotFoundException异常:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
// src/Yoda/UserBundle/Entity/UserRepository.php // ... class UserRepository extends EntityRepository implements UserProviderInterface { // ... public function loadUserByUsername($username) { $user = $this->findOneByUsernameOrEmail($username); if (!$user) { throw new UsernameNotFoundException('No user found for username '.$username); } return $user; } // ... refreshUser and supportsClass from above... } |
尝试使用电子邮件登录。他工作了!在幕后,symfony调用loadUserByUsername方法,并传递了我们提交的用户名。我们返回了一个正确的用户对象并认证他是正常的用户。我们没有去验证密码,因为这块symfony处理还和以前一样。
好了,你已经掌握了很多关于security和doctrine的知识!给自己鼓鼓掌吧,因为你已经学会了使用symfony和doctrine的复杂知识。现在你已经完成了一个优雅的登录系统,而且还能给他很多的控制,下章我们将介绍用户注册。