欢迎来到第四天教程的里世界……
因为第四天的教程可能会导致一些同学无法继续跟着完成教程里的项目,所以在里世界里我将再写一篇教程。
2020-04-12 补充:已经发布对应的 Symfony 5 精简版教程,建议对比观看。
使用 FOSUserBundle 实现用户注册功能
好吧,像用户管理这种常见的功能,我当然也有 bundle 推荐:FOSUserBundle
如同以往,安装 Bundle:
composer require friendsofsymfony/user-bundle "~2.0@dev"
注册Bundle:
// app/AppKernel.php
public function registerBundles()
{
$bundles = array(
// ...
new FOS\UserBundle\FOSUserBundle(),
);
}
FOSUserBundle 要求我们创建一个继承自 FOS\UserBundle\Model\User
的用户类:
<?php
// src/AppBundle/Entity/User.php
namespace AppBundle\Entity;
use FOS\UserBundle\Model\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
/**
* User
*
* @ORM\Entity
* @ORM\Table()
*/
class User extends BaseUser
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
}
为了使用 FOSUserBundle 来做登录,我们还得写一些配置:
# app/config/security.yml
security:
encoders:
FOS\UserBundle\Model\UserInterface:
algorithm: bcrypt
cost: 10
providers:
fos_user:
id: fos_user.user_provider.username
firewalls:
secured_area:
pattern: ^/
anonymous: ~
form_login:
provider: fos_user
csrf_provider: form.csrf_provider
logout: true
access_control:
- { path: ^/news/(new|(\d+\/edit)), roles: IS_AUTHENTICATED_FULLY }
如果你也看了第四天的教程,你会发现一些类似的东西:定义了 User Provider,指定了防火墙,防火墙可以匿名访问,但是新闻提交和编辑页需要登录权限……
不一样的地方:定义了一个 encoder
,这是用来给用户的密码加密的东西,配置里定义了什么 User
类(或者接口)使用什么样的密码加密算法。FOSUserBundle 的例子使用的是 sha256,其实常见的sha1,md5,都是可以的,但是因为彩虹表(可以搜搜看是什么东西)的存在,我推荐 bcrypt。
这里强烈建议大家还是看看第四天的内容,里面提到的一些概念的东西还是值得去了解和体会的
另外为了让 FOSUserBundle 知道我们自己定义的 User 类,我们还得配置一些东西:
# app/config/config.yml
fos_user:
db_driver: orm
firewall_name: secured_area
user_class: AppBundle\Entity\User
到此为止我们就可以创建 Mysql 的 User 表了
php app/console doctrine:schema:update --force
友情提示:在使用 --force
更新数据库之前,最好改用 --dump-sql
参数确认一下会运行的 SQL
如同 HWIOAuthBundle,FOSUserBundle 里也自带了现成的路由以及控制器代码,我们现在将他们引入进来:
# app/config/routing.yml
fos_user:
resource: "@FOSUserBundle/Resources/config/routing/all.xml"
这个时候再去访问新建新闻链接 /news/
,将会跳转到 /login
去登录。当然,你也可以直接访问 /register
去添加一个新的用户。不出意外,你已经实现了用户“注册/登录/权限控制”的功能。
在测试登录之前,需要创建用户账号,除了直接去注册页面注册新用户,FOSUserBundle 已经提供创建用户的命令
php app/console fos:user:create username user@example.com password
与 HWIOAuthBundle 合体
目前很多网站,即可以选择注册新用户,又可以使用第三方登录。我们接下来也实现这个需求。如果你依然无法测试第三方登录,可以先跳过。
FOSUserBundle 已经算是一个老牌第三方 Bundle 了,所以好多其他的 Bundle 也都多多少少会给使用 FOSUserBundle 的项目提供更多的便利。HWIOAuthBundle 也是如此。首先,我们修改我们的配置文件,让 HWIOAuthBundle 知道我们打算将第三方登录功能和 FOSUserBundle 提供的用户类结合起来:
# app/config.yml
hwi_oauth:
# 与FOSUserBundle结合,并且将 QQ 返回的用户 Id 同我们创建的 User 类的 qqId 属性绑定
fosub:
properties:
qq: qqId
# 实现 User 和 QQ 用户的绑定:如果使用QQ帐号登录,但是还没有绑定本地用户,创建新用户同登录的 QQ 帐号绑定
connect: ~
# app/config/security.yml
security:
providers:
# 第四天看过来的小伙伴注意了,这里不再需要 hwi_oauth.user.provider,有这一个 provider 就行
fos_user:
id: fos_user.user_provider.username
firewalls:
secured_area:
oauth:
oauth_user_provider:
# 这里需要改为支持 FOSUserBundle 的 provider
service: hwi_oauth.user.provider.fosub_bridge
之前我们设置了 QQ 帐号 id 需要同本地的 User 类的 qqId 属性绑定,我们来把它加上:
// src/AppBundle/Entity/User.php
/**
* @var string
*
* @ORM\Column(name="qq_id", type="string", length=50)
*/
protected $qqId;
public function setQqId($qqId)
{
$this->qqId = $qqId;
return $this;
}
public function getQqId()
{
return $this->qqId;
}
至此,我们就可以通过 QQ 登录并且创建一个绑定 QQ 帐号的本地用户了。

扩展阅读:深入 Symfony 框架用户身份验证
Symfony 框架实战教程——第四天#Alt:用 FOSUserBundle 实现用户注册和登录 by Chris Yue is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.

写作累,服务器还越来越贵
求分担,祝愿好人一生平安
天使打赏人
17 Comments
邓可
12月 8, 2017 在 5:34 下午为什么我/Register直接报错了:
Class “FrontBundle:User” not found. Is the “data_class” form option set correctly
Chris Yue
12月 8, 2017 在 9:18 下午错误信息的反馈是找不到 FrontBundle:User 这个 Entity。你确认 FrontBundle:User 是存在的?
wsh
9月 17, 2015 在 4:56 下午按照这个步骤做了,但是没有做HWI 结合那里。结果报错
You must configure the check path to be handled by the firewall using form_login in your security firewall configuration.
Chris Yue
9月 17, 2015 在 5:38 下午看提示信息是说你的防火墙用了
form_login
的方式登录但是却没有配置其必要选项check_path
wsh
9月 17, 2015 在 6:38 下午多谢博主关注:我复制了官方的代码也买找到 check_path:我不知道该写在那里 ~~~~(>_<)~~~~ !!
Chris Yue
9月 18, 2015 在 9:47 上午嗯,这篇教程里的代码我都测试过,应该是不会需要有其他的步骤的。
不过你可以试试在命令行下跑 debug:router 命令,看看登录和检查登录的路径是什么。
然后把这两个路径(路由名也行),设置在
form_login
下:惊云
5月 19, 2015 在 3:33 下午看了这个贴,我也成功用上了FOSUser,但是想要重写form的时候却一直报错。Could not load type “acme_user_registration”,跟着官网的步骤做的。
Chris Yue
5月 20, 2015 在 7:18 上午你没有注册“注册表”为服务吧?或者服务没有加form标签,肯定总有漏的地方,你再仔细看看官网给的代码示例
惊云
5月 20, 2015 在 8:35 上午博主好早~~好好,我再检查一遍
leo
5月 14, 2015 在 4:29 下午到这里就完全不对了,没看到要求登录,也无法访问 /register页面。
完全莫不着头脑哎
Chris Yue
5月 15, 2015 在 1:27 下午你访问的是哪个页面?另外
/register
页面是完全无法访问吗?freechoice
5月 14, 2015 在 1:46 下午FOSUserBundle的Login功能不管用啊,怎么登陆都是Bad Credentials
Chris Yue
5月 15, 2015 在 1:17 下午你可以用命令先创建用户再尝试登录…当然其实也很好想到直接去注册页面创建用户…不知道你是怎么创建用户的,有更多的细节可提供的吗
ccna30
4月 2, 2015 在 9:21 上午问题解决了,感谢。
这绝对是网络上最新最好的SF2教程,实战性很强,赞。
Chris Yue
4月 2, 2015 在 10:30 上午那必须的啊!还会继续连载的,欢迎继续关注
ccna30
4月 1, 2015 在 4:15 下午用cookbook的的用户登录校验就是不成功,于是改为FOSUserBundle,但是我想在验证后进入的控制器内取得刚刚验证的用户名,以便在另外一个表中查找该人的工资信息。
查了文档,不知道如何利用FOSUserBundle取得登录用户名,只能
可是显示找不到该用户,但是改成 $entities = $repository->findOneByName(‘林志玲‘);数据就能找到并显示出来。
莫非findOneByName($user)这样的不支持吗?
Chris Yue
4月 1, 2015 在 9:25 下午$user
是一个对象,而不是username,正确的写法应该是findOneByName($user->getUsername())。之所以你能直接
“hello”.$user,我估计你的$user里用了
__toString`魔术方法了