如何从数据库(实体提供程序)加载安全用户

编辑本页

警告:您正在浏览的文档欧宝体育电话欧宝娱乐app下载地址Symfony 2.8,现已不再维护。

本页的更新版本用于Sy欧宝娱乐app下载地址mfony 6.2(当前稳定版本)。

如何从数据库(实体提供程序)加载安全用户

欧宝娱乐app下载地址Symfony的安全系统可以从任何地方加载安全用户——比如通过Active Directory或OAuth服务器加载数据库。本文将向您展示如何通过Doctrine实体从数据库加载用户。

简介

提示

在你开始之前,你应该检查一下FOSUserBundle.这个外部包允许您从数据库加载用户(就像您将在这里学习的那样)而且为您提供内置的路由和控制器,如登录,注册和忘记密码。但是,如果你需要大量定制你的用户系统如果你想了解事物是如何工作的,这个教程会更好。

通过Doctrine实体加载用户有两个基本步骤:

  1. 创建用户实体
  2. 配置安全。Yml从您的实体加载

之后,你可以了解更多禁止不活跃用户使用自定义查询而且用户序列化到会话

1)创建用户实体

对于本文,假设您已经有一个用户实例中的实体AppBundle包含以下字段:id用户名密码电子邮件而且isActive

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 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
/ / src / AppBundle /实体/ User.php名称空间AppBundle实体使用学说ORM映射作为ORM使用欧宝娱乐app下载地址组件安全核心用户用户界面/ * * *@ORM\表(name = " app_user ") *@ORM\实体(repositoryClass = " AppBundle \ Repository \ UserRepository”)* /用户实现了用户界面, \可序列化的/ * * *@ORM\列(type =“整数”)*@ORM\ Id *@ORM\ GeneratedValue(策略=“汽车”)* /私人id/ * * *@ORM\Column(type="string", length=25, unique=true) */私人用户名/ * * *@ORM\Column(type="string", length=64) */私人密码/ * * *@ORM\Column(type="string", length=254, unique=true) */私人电子邮件/ * * *@ORM\Column(name="is_active", type="boolean") */私人isActive公共函数__construct()->isActive =真正的//可能不需要,请参见下面关于salt的部分// $this->salt = md5(uniqid(", true));公共函数getUsername()返回->用户名;}公共函数getSalt()//你*可能*需要一个真正的盐取决于你的编码器//参见下面关于盐的部分返回;}公共函数getPassword()返回->密码;}公共函数将getRoles()返回数组“ROLE_USER”);}公共函数eraseCredentials(){}/**@see\序列化:序列化()* /公共函数序列化()返回序列化(数组->id,->用户名、->密码,//参见下面关于盐的部分/ / $ this - >盐,));}/**@see\序列化:unserialize () * /公共函数非系列化序列化列表->id,->用户名、->密码,//参见下面关于盐的部分/ / $ this - >盐) = unserialize(序列化数组“allowed_classes”= >));}}

为了简短起见,这里没有显示一些getter和setter方法。但是您可以手动或使用自己的IDE生成这些。

谨慎

在上面的例子中,User实体的表名是“app_users”,因为“User”是一个SQL保留字。如果您希望将表名命名为“user”,它必须用反引号引用为了避免错误。注释应该如下所示@ORM \表(name = "用户”)

接下来,一定要创建数据库表

1
PHP应用程序/控制台原则:schema:update——force

这个用户界面是什么?

到目前为止,这只是一个正常的实体。但是要在安全系统中使用这个类,它必须实现用户界面.这迫使类具有以下五个方法:

要了解更多关于这些的信息,请参见用户界面

谨慎

eraseCredentials ()方法仅用于清除可能存储的纯文本密码(或类似凭据)。如果您的用户类也映射到数据库,请注意要删除哪些内容,因为修改后的对象可能会在请求期间被持久化。

序列化和反序列化方法做什么?

在每个请求结束时,User对象被序列化到会话。在下一个请求中,它是非序列化的。为了帮助PHP正确地做到这一点,您需要实现可序列化的.但是您不需要序列化所有内容:您只需要几个字段(上面所示的字段加上一些额外的字段,如果您决定实现的话AdvancedUserInterface).对于每个请求,id用于查询一个新的用户对象。

想知道更多吗?看到如何从数据库(实体提供程序)加载安全用户

2)配置安全以从您的实体加载

现在你有一个用户实现的实体用户界面你只需要告诉Symfony的安全系统欧宝娱乐app下载地址security.yml

在本例中,用户将通过HTTP基本身份验证输入他们的用户名和密码。欧宝娱乐app下载地址Symfony将查询用户实体匹配用户名,然后检查密码(更多关于密码一会儿):

  • YAML
  • XML
  • PHP
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
# app / config / security.yml安全:编码器:实体AppBundle \ \用户:算法:bcrypt#……提供者:our_db_provider:实体:类:AppBundle:用户属性:用户名#如果你使用多个实体管理器# manager_name:客户防火墙:主要:模式:^ /http_basic:供应商:our_db_provider#……

首先,编码器节告诉Symfony数据库中欧宝娱乐app下载地址的密码将使用bcrypt.第二,供应商节创建名为our_db_provider那就知道从你那里询问了AppBundle:用户实体用户名财产。这个名字our_db_provider并不重要:它只需要匹配的值提供者防火墙下的密钥。或者,如果你不设置提供者密钥,则自动使用第一个“用户提供程序”。

谨慎

如果使用的是PHP 5.4或更低版本,则需要安装ircmaxell / password-compat库,以便能够使用bcrypt编码器:

1
Composer需要ircmaxell/password-compat“~ 1.0”

创建第一个用户

若要添加用户,可以实现注册表单或者添加一些固定装置.这只是一个正常的实体,所以没有什么棘手的,除了你需要对每个用户的密码进行编码。但是不用担心,Symfony会为您欧宝娱乐app下载地址提供这样的服务。看到如何手动编码密码获取详细信息。

下面是一个导出的app_userMySQL表管理和密码管理(已被编码)。

1 2 3 4 5 6
mysql> SELECT * FROM app_users+----+----------+--------------------------------------------------------------+--------------------+-----------+ | id | |用户名密码|电子邮件| is_active  | +----+----------+--------------------------------------------------------------+--------------------+-----------+ | 1管理| |208jHZj/ wJfcVKlIwr5AvR78euJxYK7Ku5kURNhNx.7。CSIJ3Pq6LEPC | admin@example.com | 1  | +----+----------+--------------------------------------------------------------+--------------------+-----------+

如果你使用bcrypt,没有。否则,是的。所有密码都必须用盐散列,但是bcrypt在内部进行。从本教程开始使用bcrypt,getSalt ()方法用户可以直接返回(它没有被使用)。类型的注释,则需要取消注释中的行用户实体,并添加一个持久化财产。

禁止不活跃用户(AdvancedUserInterface)

如果用户isActive属性设置为(即。is_active在数据库中为0),用户仍然能够正常登录到站点。这很容易解决。

若要排除不活跃用户,请更改您的用户要实现的类AdvancedUserInterface.这个扩展用户界面,所以你只需要新的界面:

12 34 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 41 42 43 44 45
/ / src / AppBundle /实体/ User.php使用欧宝娱乐app下载地址组件安全核心用户AdvancedUserInterface/ /……用户实现了AdvancedUserInterface, \可序列化的/ /……公共函数isAccountNonExpired()返回真正的;}公共函数isAccountNonLocked()返回真正的;}公共函数isCredentialsNonExpired()返回真正的;}公共函数isEnabled()返回->isActive;}// serialize和unserialize必须更新-参见下面公共函数序列化()返回序列化(数组/ /……->isActive));}公共函数非系列化序列化列表/ /……->isActive,) = unserialize(序列化);}}

AdvancedUserInterface接口增加了四个额外的方法来验证帐户状态:

如果任何这些回归,该用户将不允许登录。您可以选择为所有这些持久化属性,或者您需要的任何属性(在本例中,仅为持久化属性)isActive从数据库中提取)。

这两种方法有什么区别呢?每个都返回一个略有不同的错误消息(当您在登录模板中呈现它们时,可以对它们进行转换,以便进一步自定义它们)。

请注意

如果你使用AdvancedUserInterface,您还需要添加这些方法使用的任何属性(如isActive)serialize ()而且unserialize ()方法。如果你这样做,您的用户可能无法从每次请求的会话中正确反序列化。

恭喜!您的数据库加载安全系统已全部设置好!接下来,添加一个true登录表单而不是HTTP Basic或继续阅读其他主题。

使用自定义查询加载用户

如果用户可以用他们的用户名登录,那就太好了电子邮件,因为两者在数据库中都是唯一的。不幸的是,本机实体提供程序只能通过用户上的单个属性处理查询。

要做到这一点,让你的UserRepository执行一个特殊的UserLoaderInterface.该接口只需要一个方法:loadUserByUsername(用户名)

12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/ / src / AppBundle /仓库/ UserRepository.php名称空间AppBundle存储库使用欧宝娱乐app下载地址学说安全用户UserLoaderInterface使用学说ORMEntityRepositoryUserRepository扩展EntityRepository实现了UserLoaderInterface公共函数loadUserByUsername用户名返回->createQueryBuilder (“u”->(在哪里'u.username =:用户名或u.email =:邮箱'->setParameter (“用户名”用户名->setParameter (“电子邮件”用户名->getQuery ()->getOneOrNullResult ();}}

2.8

UserLoaderInterface在2.8中引入。在Symfony 欧宝娱乐app下载地址2.8之前,您必须实现欧宝娱乐app下载地址\组件\安全\核心\用户\ UserProviderInterface

提示

类中添加存储库类实体的映射定义

要完成这一步,只需去掉财产中的用户提供程序中的键security.yml

  • YAML
  • XML
  • PHP
1 2 3 4 5 6 7 8
# app / config / security.yml安全:#……提供者:our_db_provider:实体:类:AppBundle:用户

这告诉Symfony欧宝娱乐app下载地址自动查询用户。相反,当有人登录时,loadUserByUsername ()方法UserRepository将被调用。

了解序列化以及如何在会话中保存用户

如果你想知道serialize ()方法中的用户类或如何序列化或反序列化User对象,那么本节是为您准备的。如果没有,可以跳过这个步骤。

一旦用户登录,整个user对象就被序列化到会话中。在下一个请求中,反序列化User对象。的值id属性用于从数据库中重新查询新的User对象。最后,将新User对象与反序列化的User对象进行比较,以确保它们表示相同的用户。例如,如果用户名由于某些原因,在2 User对象上不匹配,那么用户将出于安全原因注销。

尽管这一切都是自动发生的,但还是有一些重要的副作用。

首先,可序列化的接口及其serialize ()而且unserialize ()方法已添加,以允许用户要序列化到会话的类。这可能需要,也可能不需要,这取决于您的设置,但这可能是一个好主意。理论上,只有id需要序列化,因为refreshUser ()方法在每个请求时刷新用户id(如上所述)。这给了我们一个“新鲜的”User对象。

但是Sy欧宝娱乐app下载地址mfony也使用用户名,密码来验证用户在请求之间没有改变(它也调用你的AdvancedUserInterface方法)。未能序列化这些可能导致您在每个请求时注销。如果您的用户实现了EquatableInterface,那么不是这些属性被检查,而是您的isEqualTo ()方法,您可以检查您想要的任何属性。除非你明白这一点,否则你可能不会需要实现这个接口或担心它。

此工作,包括代码示例,是根据创作共用BY-SA 3.0许可证。