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

编辑该页面

警告:你浏览的文档欧宝体育电话欧宝娱乐app下载地址Symfony 3.4,不再维护。

这个页面的更新版本Symf欧宝娱乐app下载地址ony 6.2(当前的稳定版本)。

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

欧宝娱乐app下载地址Symfony的安全系统可以加载安全用户从任何地方,比如数据库,通过活动目录或一个OAuth服务器。这篇文章将向您展示如何从数据库中加载用户通过一个学说的实体。

介绍

提示

在开始之前,您应该检查出来FOSUserBundle。这个外部包允许你从数据库中加载用户(如在这里您将了解)给你内置路线&控制器为登录,注册,忘记密码。但是,如果你需要大量定制用户系统如果你想学习如何工作,本教程是更好。

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

  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\列(类型=“字符串”,长度= 25,独特的= true) * /私人美元用户名;/ * * *@ORM\列(类型=“字符串”,长度= 64)* /私人美元密码;/ * * *@ORM\列(类型=“字符串”,长度= 254,独特的= true) * /私人美元电子邮件;/ * * *@ORM\列(name = " is_active " type =“布尔”)* /私人美元isActive;公共函数__construct(){美元- >isActive =真正的;/ /可能不需要,请参阅下面的部分盐/ / $ this - >盐= md5(函数”,真的));}公共函数getUsername(){返回美元- >用户名;}公共函数getSalt(){/ / * *可能需要一个真正的盐根据编码器/ /请参见下面的部分盐返回;}公共函数getPassword(){返回美元- >密码;}公共函数将getRoles(){返回(“ROLE_USER”];}公共函数eraseCredentials(){}/ * *@see\序列化:序列化()* /公共函数序列化(){返回序列化([美元- >id,美元- >用户名、美元- >密码,/ /请参见下面的部分盐/ / $ this - >盐,]);}/ * *@see\序列化:unserialize () * /公共函数非系列化(美元序列化){列表(美元- >id,美元- >用户名、美元- >密码,/ /请参见下面的部分盐/ / $ this - >盐)= unserialize (美元序列化,(“allowed_classes”= >]);}}

为了让事情更短,一些getter和setter方法不显示。但是你可以生成这些手动或使用自己的IDE。

谨慎

在上面的示例中,用户实体的表名是“app_user”,因为“用户”是一个SQL保留字。如果你想打电话给你的表名“用户”,它必须用引号引用为了避免错误。注释应该是什么样的@ORM \表(name = "用户”)

接下来,确保创建数据库表:

1
美元php bin /控制台学说:模式:更新——力量

这是什么用户界面?

到目前为止,这只是一个普通的实体。但是使用这个类的安全系统,它必须实现用户界面。这迫使类有5个以下方法:

了解更多关于这些,明白了用户界面

谨慎

eraseCredentials ()方法只是为了清理可能保存纯文本密码(或类似的凭证)。小心抹去如果你的用户类也映射到数据库修改的对象可能会持续在请求。

系列化和非系列化方法做什么?

在每个请求,用户对象序列化的会话。在下一个请求,非系列化。帮助PHP正确做到这一点,你需要实现可序列化的。但是你不需要序列化一切:你只需要几个字段(上图所示的加上一些额外的如果你决定来实现AdvancedUserInterface)。在每个请求id用于查询是新鲜的吗用户从数据库对象。

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

2)配置安全加载实体

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

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

  • YAML
  • XML
  • PHP
1 2 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并不重要:它只需要匹配的值提供者关键在你的防火墙。或者,如果你不设置提供者关键在你的防火墙,第一个自动使用“用户提供者”。

创建你的第一个用户

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

下面是一个出口的app_user表从MySQL用户管理和密码管理(已编码)。

1 2 3 4 5 6
美元从app_user mysql > SELECT *;+ - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - | + | id邮件用户名密码| | | is_active | +——+ + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - + | 1 |管理|美元2美元08年美元jHZj/ wJfcVKlIwr5AvR78euJxYK7Ku5kURNhNx.7。CSIJ3Pq6LEPC | admin@example.com | 1 | +——+ + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +

如果你使用bcryptargon2i,没有。否则,是的。所有的密码必须与盐散列,但是bcryptargon2i在内部。由于本教程使用bcrypt,getSalt ()方法用户可以返回(不使用)。如果你使用不同的算法,你需要取消用户实体和添加一个持久化财产。

禁止不活跃用户(AdvancedUserInterface)

如果一个用户的isActive属性设置为(即。is_active0数据库中),用户仍然能够正常登录到网站。

排除不活跃用户,改变你用户类来实现AdvancedUserInterface。这个扩展用户界面,所以你只需要新接口:

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

AdvancedUserInterface界面添加四个额外的方法来验证帐户状态:

如果任何这些返回的,用户不允许登录。你可以选择坚持为所有这些属性,或任何你需要(在本例中,只有isActive将从数据库中)。

方法之间的区别是什么?每个返回一个稍微不同的错误消息(这些可以翻译当你渲染他们登录模板进一步定制它们)。

请注意

如果你使用AdvancedUserInterface,您还需要添加的任何属性使用这些方法(如isActive)serialize ()unserialize ()方法。如果你正确做到这一点,您的用户可能不是反序列化的会话对每个请求。

恭喜!database-loading安全系统都设置!接下来,添加一个真的登录表单而不是HTTP基本或继续阅读其他话题。

使用自定义查询加载用户

这将是伟大的如果一个用户可以用自己的用户名登录电子邮件,因为这两个数据库中是独一无二的。不幸的是,本地实体供应商只能够处理通过一个属性对用户查询。

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

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

提示

不要忘记添加库类你的实体的映射定义

要完成这一点,只是删除财产主要从用户提供者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 ()方法在用户类或多用户对象被序列化或反序列化,那么这部分是给你的。如果不是,请跳过。

一旦用户登录,整个用户对象被序列化到会话中。在下一个请求,用户对象是反序列化。然后,的值id为新用户属性用于重新查询从数据库对象。最后,新鲜的用户对象相比,反序列化对象,以确保它们代表相同的用户。例如,如果用户名2用户对象不匹配出于某种原因,然后用户将被注销,是为了安全起见。

尽管这些都是自动进行的,有几个重要的副作用。

首先,可序列化的接口和其serialize ()unserialize ()已经添加到允许的方法用户类进行序列化会话。这可能会或可能不会需要根据您的设置,但它可能是一个好主意。从理论上讲,只有id需要序列化,因为refreshUser ()方法针对每个请求刷新用户使用id(如前所述)。这给了我们一个“新鲜”的用户对象。

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

这项工作,包括代码示例,许可下Creative Commons冲锋队3.0许可证。