如何从数据库中加载安全用户(实体提供者)
编辑该页面警告:你浏览的文档欧宝官网下载appob娱乐下载Symfony 2.0,不再维护。
读这个页面的更新版本Symfob娱乐下载ony 6.2(当前的稳定版本)。
如何从数据库中加载安全用户(实体提供者)
安全层是最聪明的Symfony的工具之一。ob娱乐下载它处理两件事:身份验证和授权过程。虽然它似乎很难理解它是如何工作的内部,安全系统是非常灵活的,允许你与任何身份验证后端应用程序集成,如Active Directory, OAuth服务器或数据库。
介绍
本文主要关注如何验证用户对数据库表由原则管理实体类。这个食谱条目的内容分成了三个部分。第一部分是关于设计原则用户
实体类,使它可用在Symfony的安全层。ob娱乐下载第二部分描述了如何轻松地验证一个用户的教义EntityUserProvider对象与框架和一些配置绑定。最后,本教程将展示如何创建一个定制的EntityUserProvider对象从数据库中检索用户自定义条件。
本教程假设有一个引导和加载Acme \ UserBundle
包在应用程序的内核。
数据模型
这个食谱的目的,AcmeUserBundle
包包含一个用户
实体类以下字段:id
,用户名
,盐
,密码
,电子邮件
和isActive
。的isActive
字段告诉用户帐号是否活跃。
让它短,每个已被移除的getter和setter方法关注的最重要的方法用户界面。
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 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
/ / src / Acme / / User.php UserBundle /实体名称空间Acme\UserBundle\实体;使用学说\ORM\映射作为ORM;使用ob娱乐下载\组件\安全\核心\用户\用户界面;/ * * * Acme \ UserBundle \实体\用户* *@ORM\表(name = " acme_users ") *@ORMAcme \ UserBundle \ \实体(repositoryClass = "实体\ UserRepository ") * /类用户实现了用户界面,\可序列化的{/ * * *@ORM\列(type =“整数”)*@ORM\ Id *@ORM\ GeneratedValue(策略=“汽车”)* /私人美元id;/ * * *@ORM\列(类型=“字符串”,长度= 25,独特的= true) * /私人美元用户名;/ * * *@ORM\列(类型=“字符串”,长度= 32)* /私人美元盐;/ * * *@ORM\列(类型=“字符串”,长度= 40)* /私人美元密码;/ * * *@ORM\列(类型=“字符串”,长度= 60,独特的= true) * /私人美元电子邮件;/ * * *@ORM\列(name = " is_active " type =“布尔”)* /私人美元isActive;公共函数__construct(){美元这- >isActive =真正的;美元这- >盐= md5(函数零,真正的));}/ * * *@inheritDoc* /公共函数getUsername(){返回美元这- >用户名;}/ * * *@inheritDoc* /公共函数getSalt(){返回美元这- >盐;}/ * * *@inheritDoc* /公共函数getPassword(){返回美元这- >密码;}/ * * *@inheritDoc* /公共函数将getRoles(){返回数组(“ROLE_USER”);}/ * * *@inheritDoc* /公共函数eraseCredentials(){}/ * * *@inheritDoc* /公共函数=(用户界面美元用户){返回美元这- >id = = =美元用户- >getId ();}/ * * *@see\序列化:序列化()* /公共函数序列化(){返回序列化(数组(美元这- >id));}/ * * *@see\序列化:unserialize () * /公共函数非系列化(美元序列化){列表(美元这- >id) = unserialize (美元序列化);}}
为了使用的一个实例AcmeUserBundle:用户
Symfony安全层类,实ob娱乐下载体类必须实现用户界面。这个接口部队后的类来实现六个方法:
getUsername ()
getSalt ()
getPassword ()
将getRoles ()
eraseCredentials ()
equals ()
每一个细节,明白了用户界面。
为了保持简单,equals ()
方法就比较id
领域,但也有可能做更多的检查根据你的数据模型的复杂性。另一方面,eraseCredentials ()
本教程的目的方法仍然是空的。
请注意
的可序列化的接口和其序列化
和非系列化
已经添加到允许的方法用户
类进行序列化会话。这可能会或可能不会需要根据您的设置,但它可能是一个好主意。只有id
需要序列化,因为refreshUser ()方法针对每个请求重新加载用户使用id
。
下面是我的一个出口用户
从MySQL表。有关如何创建用户记录和编码的密码,看看安全。
1 2 3 4 5 6 7 8 9 10
$ mysql > select *从用户;+ - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + | id盐| | |用户名密码|电子邮件| is_active | +——+ + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + | 1 | hhamon e59b97f6957fb42d66f894793079 | 7308 | 09610 f61637408828a35d7debee5b38a8350eebe | hhamon@example.com | 1 | | 2 | jsmith | ce617a6cca9126bf4036ca0c02e82dee | 8390105917 f3a3d533815250ed7c64b4594d7ebf | jsmith@example.com | 1 | | 3 |马克西姆| cd01749bb995dc658fa56ed45458d807 | 9764731 e5f7fb944de5fd8efad4949b995b72a3c | maxime@example.com | 0 | | 4 |唐纳德| 6683年c2bfd90c0426088402930cadd0f8 | 5 c3bcec385f59edcc04490d1db95fdb8673bf612 | donald@example.com | 1 | +——+ + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + 4行在集(0.00秒)
数据库现在包含四个用户使用不同的用户名,电子邮件和状态。下一部分将关注如何验证一个用户由于教义实体用户提供者和几行配置。
对某人对数据库进行身份验证
验证Symfony的学说对数据库用户安全层是小菜一碟。ob娱乐下载一切都驻留在的配置SecurityBundle存储在应用程序/配置/ security.yml
文件。
下面是一个示例的配置,用户将进入他/她的用户名和密码通过HTTP基本身份验证。这些信息将会针对您的用户数据库中的实体记录检查:
- 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安全:编码器:Acme \ UserBundle \实体\用户:算法:sha1encode_as_base64:假迭代:1role_hierarchy:ROLE_ADMIN:ROLE_USERROLE_SUPER_ADMIN:(ROLE_USER,ROLE_ADMIN,ROLE_ALLOWED_TO_SWITCH]提供者:管理员:实体:{类:AcmeUserBundle:用户,属性:用户名}防火墙:admin_area:模式:^ /管理http_basic:~access_control:- - - - - -{路径:^ /管理,角色:ROLE_ADMIN}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
< !- - - - - -- - - - - -app/config/security.xml -->< /span><配置><编码器类=“Acme \ UserBundle \实体\用户”算法=“sha1”encode-as-base64=“假”迭代=“1”/ ><角色id=“ROLE_ADMIN”>ROLE_USER< /角色><角色id=“ROLE_SUPER_ADMIN”>ROLE_USER、ROLE_ADMIN ROLE_ALLOWED_TO_SWITCH< /角色><提供者的名字=“管理员”><实体类=“AcmeUserBundle:用户”财产=“用户名”/ >< /提供者><防火墙的名字=“admin_area”模式=“^ /管理”><http基本/ >< /防火墙><规则路径=“^ /管理”角色=“ROLE_ADMIN”/ >< /配置>
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
/ / app / config / security.php美元容器- >loadFromExtension (“安全”,数组(“编码器”= >数组(“Acme \ UserBundle \实体\用户”= >数组(“算法”= >“sha1”,“encode_as_base64”= >假,“迭代”= >1),),“role_hierarchy”= >数组(“ROLE_ADMIN”= >“ROLE_USER”,“ROLE_SUPER_ADMIN”= >数组(“ROLE_USER”,“ROLE_ADMIN”,“ROLE_ALLOWED_TO_SWITCH”),),“供应商”= >数组(“管理员”= >数组(“实体”= >数组(“类”= >“AcmeUserBundle:用户”,“属性”= >“用户名”))),“防火墙”= >数组(“admin_area”= >数组(“模式”= >“^ /管理”,“http_basic”= >零),),“access_control”= >数组(数组(“路径”= >“^ /管理”,“角色”= >“ROLE_ADMIN”))));
的编码器
部分同事sha1
密码编码器到实体类。这意味着Symfony将期望的密ob娱乐下载码存储在数据库中使用该算法编码。有关如何创建一个新的用户对象的正确编码密码,看到安全安全的章节。
的供应商
部分定义了一个管理员
用户提供者。用户提供的“源”期间加载,用户身份验证。在这种情况下,实体
关键字意味着Symfony将使用原则实ob娱乐下载体用户提供者加载用户从数据库实体对象使用用户名
独特的领域。换句话说,这告诉Symfony如何从数据库中获取用户之ob娱乐下载前检查密码有效性。
这段代码和配置工作,但是还不够安全的应用程序活跃的用户。到目前为止,你仍然可以进行身份验证马克西姆
。下一节将解释如何禁止非活跃用户。
禁止非活跃用户
最简单的方法排除非活跃用户是实现AdvancedUserInterface接口,负责检查用户的帐户状态。的AdvancedUserInterface扩展了用户界面接口,所以你只需要切换到新界面AcmeUserBundle:用户
实体类受益于简单和高级身份验证行为。
的AdvancedUserInterface界面添加四个额外的方法来验证帐户状态:
isAccountNonExpired ()
检查用户的帐户已经过期,是否isAccountNonLocked ()
检查用户是否被锁定后,isCredentialsNonExpired ()
检查用户的凭证(密码)是否已经过期,isEnabled ()
检查是否启用了用户。
在这个例子中,第一个三种方法将返回真正的
而isEnabled ()
方法将返回的布尔值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
/ / src / Acme / / User.php UserBundle /实体名称空间Acme\UserBundle\实体;/ /……使用ob娱乐下载\组件\安全\核心\用户\AdvancedUserInterface;类用户实现了AdvancedUserInterface{/ /……公共函数isAccountNonExpired(){返回真正的;}公共函数isAccountNonLocked(){返回真正的;}公共函数isCredentialsNonExpired(){返回真正的;}公共函数isEnabled(){返回美元这- >isActive;}}
如果你想验证马克西姆
,现在禁止访问这个用户没有激活账户。下次会议将重点讨论如何编写一个自定义实体供应商验证一个用户的用户名或电子邮件地址。
验证一个人与一个自定义实体提供者
下一步是允许用户进行身份验证和他的用户名或电子邮件地址都是独特的在数据库中。不幸的是,本地实体提供者只能处理一个属性来获取用户从数据库中。
为此,创建一个自定义实体供应商查找用户的用户名或电子邮件字段匹配提交登录用户名。好消息是,教义re欧宝平台是合法的吗pository对象可以作为一个实体的用户提供者如果它实现了UserProviderInterface。这个接口有三种方法来实现:loadUserByUsername(用户名)
,refreshUser(用户界面用户)美元
,supportsClass(类)
。更多细节,请参阅UserProviderInterface。
下面的代码显示的实现UserProviderInterface在UserRepository
类:
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
/ / src / Acme / / UserRepository.php UserBundle /实体名称空间Acme\UserBundle\实体;使用ob娱乐下载\组件\安全\核心\用户\用户界面;使用ob娱乐下载\组件\安全\核心\用户\UserProviderInterface;使用ob娱乐下载\组件\安全\核心\异常\UsernameNotFoundException;使用ob娱乐下载\组件\安全\核心\异常\UnsupportedUserException;使用学说\ORM\EntityRepository;使用学说\ORM\NoResultException;类UserRepository扩展EntityRepository实现了UserProviderInterface{公共函数loadUserByUsername(美元用户名){美元问=美元这- >createQueryBuilder (“u”)- >(在哪里“u。使用rname = :username OR u.email = :email'< /span>)- >setParameter (“用户名”,美元用户名)- >setParameter (“电子邮件”,美元用户名)- >getQuery ();试一试{/ /查询:getSingleResult()方法将抛出一个异常/ /如果没有匹配的记录标准。美元用户=美元问- >getSingleResult ();}抓(NoResultException美元e){美元消息= sprintf (无法找到一个活跃的管理AcmeUserBundle:用户对象由“% s”标识。,美元用户名);扔新UsernameNotFoundException (美元消息,零,0,美元e);}返回美元用户;}公共函数refreshUser(用户界面美元用户){美元类= get_class (美元用户);如果(!美元这- >supportsClass (美元类)){扔新UnsupportedUserException (sprintf (不支持“% s”的实例。,美元类));}返回美元这- >找到(美元用户- >getId ());}公共函数supportsClass(美元类){返回美元这- >getEntityName () = = =美元类| | is_subclass_of (美元类,美元这- >getEntityName ());}}
完成实现,安全层的配置必须改变告诉Symfony使用新的自定义实体提供者而不是通用原则实体提供者。ob娱乐下载这是微不足道的来实现的财产
字段security.providers.administrators.entity
部分的security.yml
文件。
- YAML
- XML
- PHP
1 2 3 4 5 6 7
# app / config / security.yml安全:#……提供者:管理员:实体:{类:AcmeUserBundle:用户}#……
1 2 3 4 5 6 7 8 9 10
< !- - - - - -- - - - - -app/config/security.xml -->< /span><配置>< !- - - - - -- - - - - -。。。- - ><提供者的名字=“管理员”><实体类=“AcmeUserBundle:用户”/ >< /提供者>< !- - - - - -- - - - - -。。。- - >< /配置>
1 2 3 4 5 6 7 8 9 10 11 12
/ / app / config / security.php美元容器- >loadFromExtension (“安全”,数组(…“供应商”= >数组(“管理员”= >数组(“实体”= >数组(“类”= >“AcmeUserBundle:用户”)))……));
这样,安全层将使用的一个实例UserRepository
和调用它的loadUserByUsername ()
方法从数据库中获取一个用户是否他填写的用户名或电子邮件地址。
数据库中管理角色
最后本教程的重点是如何存储和检索从数据库角色的列表。如前所述,当加载您的用户,它的将getRoles ()
方法返回的数组安全角色,应该分配给用户。你可以加载这些数据从任何地方——用于所有用户(如硬编码列表。阵列(“ROLE_USER”)
),一个原则称为数组属性角色
或通过一个学说的关系,您将了解在这一节中。
谨慎
在一个典型的设置,你应该总是返回至少1的作用将getRoles ()
方法。按照惯例,一个角色ROLE_USER
通常返回。如果你不返回任何角色,它可能会出现,如果您的用户没有经过身份验证的。
在这个例子中,AcmeUserBundle:用户
实体类定义了一个多对多关系AcmeUserBundle:组
实体类。一个用户可以是多个组相关和一组可以由一个或多个用户。作为一个团体也是一个角色,前面的将getRoles ()
方法现在返回的列表相关的组:
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
/ / src / Acme / / User.php UserBundle /实体名称空间Acme\UserBundle\实体;使用学说\常见的\集合\ArrayCollection;/ /……类用户实现了AdvancedUserInterface,\可序列化的{/ * * *@ORM\多(targetEntity =“集团”,inversedBy =“用户”)* * /私人美元组;公共函数__construct(){美元这- >组=新ArrayCollection ();}/ /……公共函数将getRoles(){返回美元这- >组- >toArray ();}/ * * *@see\序列化:序列化()* /公共函数序列化(){返回序列化(数组(美元这- >id));}/ * * *@see\序列化:unserialize () * /公共函数非系列化(美元序列化){列表(美元这- >id) = unserialize (美元序列化);}}
的AcmeUserBundle:组
实体类定义了三个表的字段(id
,的名字
和角色
)。独特的角色
字段包含使用的角色名Symfony安全层安全的应用程序。ob娱乐下载最重要的是要注意的AcmeUserBundle:组
实体类扩展了角色:
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
/ / src / Acme /包/ / Group.php UserBundle /实体名称空间Acme\UserBundle\实体;使用ob娱乐下载\组件\安全\核心\角色\角色;使用学说\常见的\集合\ArrayCollection;使用学说\ORM\映射作为ORM;/ * * *@ORM\表(name = " acme_groups ") *@ORM()* / \实体类集团扩展角色{/ * * *@ORM\列(name = " id ",类型=“整数”)*@ORM* \ Id ()@ORM\ GeneratedValue(策略=“汽车”)* /私人美元id;/ * * *@ORM\列(name =“名称”,输入=“字符串”,长度= 30)* /私人美元的名字;/ * * *@ORM\列(name =“角色”,类型=“字符串”,长度= 20,独特的= true) * /私人美元角色;/ * * *@ORM\多(targetEntity = "用户",mappedBy =“集团”)* /私人美元用户;公共函数__construct(){美元这- >用户=新ArrayCollection ();}/ /……每个属性的getter和setter/ * * *@seeRoleInterface * /公共函数getRole(){返回美元这- >角色;}}
改善性能和避免延迟加载组检索用户自定义实体的提供商时,最好的办法是加入的组织关系UserRepository: loadUserByUsername ()
方法。这将获取相关联的用户和他的角色/组与单个查询:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21日22日23日
/ / src / Acme / / UserRepository.php UserBundle /实体名称空间Acme\UserBundle\实体;/ /……类UserRepository扩展EntityRepository实现了UserProviderInterface{公共函数loadUserByUsername(美元用户名){美元问=美元这- >createQueryBuilder (“u”)- >选择(“u g”)- >leftJoin (“u.groups”,‘g’)- >(在哪里“u。使用rname = :username OR u.email = :email'< /span>)- >setParameter (“用户名”,美元用户名)- >setParameter (“电子邮件”,美元用户名)- >getQuery ();/ /……}/ /……}
的QueryBuilder: leftJoin ()
方法连接并获取相关团体的AcmeUserBundle:用户
模型类检索当用户用他的电子邮件地址或用户名。