既然错误已经不存在了,就尝试一下登录吧!等等,我们的用户表还是空的呢。所以不管我们怎们登录都会看到一个错误的密码信息。
当然这个程序是没有问题的。我们需要添加一些数据:让我们复制loadEvents fixtures 类(LoadEvents.php)到userbundle中,重命名loadUsers,并修改命名空间:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// src/Yoda/UserBundle/DataFixtures/ORM/LoadUsers.php namespace Yoda\UserBundle\DataFixtures\ORM; use Doctrine\Common\DataFixtures\FixtureInterface; use Doctrine\Common\Persistence\ObjectManager; use Yoda\UserBundle\Entity\User; class LoadUsers implements FixtureInterface { public function load(ObjectManager $manager) { // todo } } |
保存用户很简单:只要创建一个对象,给他一个username并persist和flush它。最棘手的是password字段,需要用bcrypt加密它:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
// src/Yoda/UserBundle/DataFixtures/ORM/LoadUsers.php // ... use Yoda\UserBundle\Entity\User; // ... public function load(ObjectManager $manager) { $user = new User(); $user->setUsername('darth'); // todo - fill in this encoded password... ya know... somehow... $user->setPassword(''); $manager->persist($user); // the queries aren't done until now $manager->flush(); } |
ContainerAwareInterface Fixtures
下面告诉你什么叫酷,symfony给我们提供了一个对象,它能够做所有的编码操作。当然要使用它,首先要实现ContainerAwareInterface:
1 2 3 4 5 6 7 8 9 |
// src/Yoda/UserBundle/DataFixtures/ORM/LoadUsers.php // ... use Symfony\Component\DependencyInjection\ContainerAwareInterface; class LoadUsers implements FixtureInterface, ContainerAwareInterface { // … } |
这里我们还需要一个setContainer方法。我们还需要存储这个$containser变量到一个新的$container属性:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
// src/Yoda/UserBundle/DataFixtures/ORM/LoadUsers.php // ... use Symfony\Component\DependencyInjection\ContainerAwareInterface; use Symfony\Component\DependencyInjection\ContainerInterface; class LoadUsers implements FixtureInterface, ContainerAwareInterface { private $container; // ... public function setContainer(ContainerInterface $container = null) { $this->container = $container; } } |
因为我们实现了这个接口,symfony会在container对象加载load之前调用这个方法。请记住这个container是一个类似于数组的对象,它在系统中持有所有有用的对象。我们可以运行container:debug来看到这个对象的列表:
1 |
php app/console container:debug |
编译密码
让我们创建一个辅助函数encodePassword去编译你已知的密码!首先,我们问问symfony怎么用一个特殊的“encoder”对象,加密这个密码。我们的bcrypt不是配置在security.yml中吗?是的,我们就是获取它的数据:
之后,我们获得encoder,并调用encodePassword(),他就能帮我们完成所有工作了:
symfony2.6写法:
1 2 3 4 5 6 7 8 |
// src/Yoda/UserBundle/DataFixtures/ORM/LoadUsers.php // ... private function encodePassword(User $user,$plainPassword) { $encoder = $this->container->get(‘security.password_encoder’); return $encoder->encodePassword($user, $plainPassword); } |
旧版本写法:
1 2 3 4 5 6 7 8 9 10 11 |
// src/Yoda/UserBundle/DataFixtures/ORM/LoadUsers.php // ... private function encodePassword(User $user, $plainPassword) { $encoder = $this->container->get('security.encoder_factory') ->getEncoder($user) ; return $encoder->encodePassword($plainPassword, $user->getSalt()); } |
symfony会将明文的密码,还有一个随机串(salt)一起使用bcrypt加密。好的,我们现在调用这个方法来完成密码加密:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// src/Yoda/UserBundle/DataFixtures/ORM/LoadUsers.php // ... public function load(ObjectManager $manager) { $user = new User(); $user->setUsername('darth'); $user->setPassword($this->encodePassword($user, 'darthpass')); $manager->persist($user); // the queries aren't done until now $manager->flush(); } |
输入命令行装载数据:
1 |
php app/console doctrine:fixtures:load |
让我们用命令看看我们的数据:
1 |
php app/console doctrine:query:sql "SELECT * FROM yoda_user" |
1 2 3 4 |
array (size=1) 0 => array (size=3) ‘id’ => string ‘1’ (length=1) ‘username’ => string ‘user’ (length=4) ‘password’ => string ‘$2y$13$BoVE3I5dmVkBjRp.l6uwyOI8Z8Ngokiaa.OUUuHoDbGDBdMRMUrmC’ (length=60) |
太好了,我们已经看到了编译好的密码,其实还有一个随机生成的salt。你每个用户都存储一个salt随机数。那么在symfony中使用getSalt函数调用,这个函数和bcrypt没有关系。
回到浏览器,我们可以登录了!看看,我们做了些什么呢:
- 传入一个username,从数据库中调用数据并得到一个User Entity;
- 把明文的密码用bcrypt方式编译
- 把这个版本的密码和数据库中的密码比对,如果匹配成功,你就可以登录进来了!
private function encodePassword(User $user,$plainTextPassword)
{
$encoder = $this->container->get(‘security.password_encoder’);
return $encoder->encodePassword($user, $plainTextPassword);
}
symfony 2.6 更新
谢谢你,指出的很到位,你的代码很正确。并且我也在http://symfony.com/doc/current/book/security.html#dynamically-encoding-a-password
找到了答案。
已经在本章添加了symfony2.6版本的写法。