安全

编辑本页

警告:您正在浏览的文档欧宝体育电话<一个href="//www.oldmanjams.com/releases/4.4">欧宝娱乐app下载地址Symfony 4.4,现已不再维护。

读<一个href="//www.oldmanjams.com/doc/current/security.html">本页的更新版本用于Sy欧宝娱乐app下载地址mfony 6.2(当前稳定版本)。

安全

截屏视频

你更喜欢视频教程吗?请查看<一个href="https://symfonycasts.com/screencast/symfony-security" class="reference external" rel="external noopener noreferrer" target="_blank">欧宝娱乐app下载地址Symfony安全视频系列

欧宝娱乐app下载地址Symfony的安全系统非常强大,但设置起来也很麻烦。别担心!在本文中,您将学习如何逐步设置应用程序的安全系统:

  1. 安装安全支持
  2. 创建用户类
  3. 身份验证和防火墙
  4. 拒绝访问你的应用(授权)
  5. 获取当前User对象

之后将讨论其他一些重要的话题。

2a)创建用户类

不管如何您将验证(例如登录表单或API令牌)或在哪里你的用户数据将被存储(数据库,单点登录),下一步总是相同的:创建一个“user”类。最简单的方法是使用<一个href="//www.oldmanjams.com/doc/current/bundles/SymfonyMakerBundle/index.html" class="reference external">MakerBundle

让我们假设你想用Doctrine在数据库中存储你的用户数据:

12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
php bin/console make:user安全用户类的名称(例如user) [user]: > user是否要存储用户数据数据库(通过Doctrine)?(yes/no) [yes]: > yes输入一个唯一的属性名“显示”的名字用户(例如电子邮件,用户名,uuid[电子邮件]>电子邮件这个应用程序需要哈希/检查用户密码?(yes/no) [yes]: > yes created: src/Entity/User.php created: src/Repository/UserRepository.php updated: src/Entity/User.php updated: config/packages/security.yaml

就是这样!该命令会询问几个问题,以便生成您所需要的内容。最重要的是User.php文件本身。的只有规则关于你用户阶级就是它必须实现<一个href="https://github.com/symfony/symfony/blob/4.4/src/Symfony/Component/Security/Core/User/UserInterface.php" class="reference external" title="用户界面" rel="external noopener noreferrer" target="_blank">用户界面.请随意补充任何你需要的其他领域或逻辑。如果你的用户类是一个实体(如本例中所示),则可以使用<一个href="//www.oldmanjams.com/doc/4.4/doctrine.html" class="reference internal">:实体命令要添加更多字段。另外,确保对新实体进行迁移并运行:

1 2
PHP bin/控制台make:迁移PHP bin/控制台原则:迁移:迁移

2b)“用户提供者”

除了你的用户类,你还需要一个“User提供者”:一个帮助做一些事情的类,比如从会话中重新加载User数据和一些可选的特性,比如<一个href="//www.oldmanjams.com/doc/4.4/security/remember_me.html" class="reference internal">记得我而且<一个href="//www.oldmanjams.com/doc/4.4/security/impersonating_user.html" class="reference internal">模拟

幸运的是,:用户命令中已经为您配置了security.yaml供应商关键:

  • YAML
  • XML
  • PHP
1 2 3 4 5 6 7 8 9 10
#配置/包/ security.yaml安全:#……提供者:#用于从会话和其他功能中重新加载用户(例如switch_user)app_user_provider:实体:类:应用实体\ \用户属性:电子邮件

如果你的用户类是一个实体,你不需要做任何其他事情。但如果你的课是一个实体:用户还会产生一个吗UserProvider您需要完成的类。在这里了解更多关于用户提供商的信息:<一个href="//www.oldmanjams.com/doc/4.4/security/user_provider.html" class="reference internal">用户服务提供商

2c)编码密码

并非所有应用程序都有需要密码的“用户”。如果你的用户有密码,你可以控制这些密码的编码方式security.yaml.的:用户命令将为您预配置:

  • YAML
  • XML
  • PHP
1 2 3 4 5 6 7 8 9 10 11
#配置/包/ security.yaml安全:#……编码器:在这里使用你的用户类名应用实体\ \用户:#使用本地密码编码器#该值自动选择最好的哈希算法#(即钠可用时)。算法:汽车

现在Symfony欧宝娱乐app下载地址知道了如何要对密码进行编码,可以使用UserPasswordEncoderInterface服务在将用户保存到数据库之前执行此操作。

例如,通过使用<一个href="//www.oldmanjams.com/doc/4.4/testing.html" class="reference internal">DoctrineFixturesBundle,可以创建虚拟数据库用户:

1 2 3 4
要创建的fixture的类名(例如AppFixtures): > UserFixtures

使用此服务来编码密码:

12 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
/ / src / DataFixtures / UserFixtures.php+使用Sym欧宝娱乐app下载地址fony\Component\Security\Core\Encoder\UserPasswordEncoderInterface/ /……类UserFixtures扩展Fixture {+ private $passwordEncoder;+公共函数__construct(UserPasswordEncoderInterface $passwordEncoder)+ {+ $this->passwordEncoder = $passwordEncoder;+}公共函数加载(ObjectManager $manager) {$user =新用户();/ /……+ $ user - >向setPassword ($ this - > passwordEncoder - > encodePassword (+ $ user,+“the_new_password”+));/ /……}}

您可以通过执行以下命令手动编码密码:

1
PHP bin/console security: code-password

3a)认证和防火墙

安全系统配置在配置/包/ security.yaml.的大多数重要的部分是防火墙

  • YAML
  • XML
  • PHP
1 2 3 4 5 6 7 8
#配置/包/ security.yaml安全:防火墙:戴夫:模式:^ /(_(分析器| wdt) | css |图片| js) /安全:主要:匿名:懒惰的

4.4

懒惰的在Symfony 4.4中引入了匿名模式。欧宝娱乐app下载地址

“防火墙”是您的身份验证系统:它下面的配置定义如何您的用户将能够验证(例如登录表单,API令牌等)。

对于每个请求,只有一个防火墙是活动的:Symfony使用欧宝娱乐app下载地址模式键找到第一个匹配(也可以<一个href="//www.oldmanjams.com/doc/4.4/security/firewall_restriction.html" class="reference internal">由主机或其他东西匹配).的dev防火墙实际上是一个假防火墙:它确保你不会不小心阻止Symfony的开发工具——这些工具存在于像欧宝娱乐app下载地址/ _profiler而且/ _wdt

所有真正的类处理url主要防火墙(不模式键表示匹配所有url)。防火墙可以有多种身份验证模式,换句话说,它支持多种方式来询问“您是谁?”通常,当用户第一次访问你的网站时,他们是未知的(即没有登录)。的匿名Mode(如果启用)用于这些请求。

事实上,如果你现在去主页,你拥有访问权限,您将看到您被“验证”为不久。.防火墙验证了它不知道你的身份,所以你是匿名的:

这意味着任何请求都可以使用匿名令牌来访问某些资源,而某些操作(即某些页面或按钮)仍然需要特定的特权。然后,用户可以在不作为唯一用户进行身份验证的情况下访问表单登录(否则将发生无限重定向循环,要求用户在尝试进行身份验证时进行身份验证)。

稍后您将学习如何拒绝对某些url、控制器或部分模板的访问。

提示

懒惰的匿名模式阻止会话在不需要授权(即显式检查用户权限)的情况下启动。这对于保持请求可缓存是很重要的(参见<一个href="//www.oldmanjams.com/doc/4.4/http_cache.html" class="reference internal">HTTP缓存).

请注意

如果看不到工具栏,请安装<一个href="//www.oldmanjams.com/doc/4.4/profiler.html" class="reference internal">分析器

1
开发symfony/profiler-pack欧宝娱乐app下载地址

现在我们了解了防火墙,下一步是为用户创建一种身份验证方法!

4)拒绝访问、角色和其他授权

用户现在可以使用登录表单登录到您的应用程序。太棒了!现在,您需要学习如何拒绝访问并使用User对象。这叫做授权,它的任务是决定用户是否可以访问某些资源(URL、模型对象、方法调用等等)。

授权的过程有两个不同的方面:

  1. 用户在登录时接收到一组特定的角色(例如:ROLE_ADMIN).
  2. 您可以添加代码,以便资源(例如URL,控制器)需要特定的“属性”(最常见的是像这样的角色)ROLE_ADMIN)以供查阅。

添加代码拒绝访问

两个拒绝访问某物的方法:

  1. 在security.yaml中的访问控制允许你保护URL模式(例如:/管理/ *).更简单,但更不灵活;
  2. 在控制器(或其他代码)中

保护URL模式(access_control)

保护部分应用的最基本方法是保护整个URL模式security.yaml.例如,to requireROLE_ADMIN所有以。开头的url/管理,你可以:

  • YAML
  • XML
  • PHP
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
#配置/包/ security.yaml安全:#……防火墙:#……主要:#……access_control:#需要/admin*的ROLE_ADMIN-路径:“^ /管理”角色:ROLE_ADMIN#或为/admin*提供一个表达式(例如需要多个角色)-路径:“^ /管理”角色:' is_granting ("IS_AUTHENTICATED_FULLY") and is_granting ("ROLE_ADMIN")'# path的值可以是任何有效的正则表达式#(这将匹配类似/api/post/7298和/api/comment/528491的url)-路径:^ / api / (post) |评论/ \ d + $,角色:ROLE_USER

您可以根据需要定义任意数量的URL模式—每个都是一个正则表达式。,只有一个Symfony从列表的顶部开始,在找到第一个匹配时停止:欧宝娱乐app下载地址

  • YAML
  • XML
  • PHP
1 2 3 4 5 6 7 8 9 10
#配置/包/ security.yaml安全:#……access_control:#匹配/admin/users/*-路径:' ^ /管理/用户的角色:ROLE_SUPER_ADMIN#匹配/admin/*,除了匹配上述规则的任何内容-路径:“^ /管理”角色:ROLE_ADMIN

在路径前面加上意味着只有url开始与图案相匹配。例如,的路径/管理(没有)会相配/管理/ foo但也会匹配url/ foo /管理

每一个access_control也可以匹配IP地址,主机名和HTTP方法。还可以使用它将用户重定向到httpsURL模式的版本。看到<一个href="//www.oldmanjams.com/doc/4.4/security/access_control.html" class="reference internal">安全访问控制如何工作?

保护控制器和其他代码

你可以拒绝来自控制器内部的访问:

1 2 3 4 5 6 7 8 9 10
/ / src /控制器/ AdminController.php/ /……公共函数adminDashboard()响应->denyAccessUnlessGranted (“ROLE_ADMIN”);//或添加一个可选消息-由开发人员看到->denyAccessUnlessGranted (“ROLE_ADMIN”'用户试图在没有ROLE_ADMIN权限的情况下访问页面');}

就是这样!如果访问权限没有被授予,一个特殊的<一个href="https://github.com/symfony/symfony/blob/4.4/src/Symfony/Component/Security/Core/Exception/AccessDeniedException.php" class="reference external" title="AccessDeniedException" rel="external noopener noreferrer" target="_blank">AccessDeniedException抛出,并且不再调用控制器中的其他代码。然后,两件事中的一件会发生:

  1. 如果用户还没有登录,他们将被要求登录(例如重定向到登录页面)。
  2. 如果用户登录,但确实ROLE_ADMIN角色时,将显示403拒绝访问页面(您可以这样做<一个href="//www.oldmanjams.com/doc/4.4/controller/error_pages.html" class="reference internal">定制).

多亏了SensioFrameworkExtraBundle,你也可以使用注释来保护你的控制器:

12 3 4 5 6 7 8 9 10 11 12 13 14 16 17 18 19 20 21 22
// src/Controller/AdminController.php //…+使用Sensio\Bundle\FrameworkExtraBundle\Configuration\ isgranting;+ / * *+ *需要ROLE_ADMIN的*每个*控制器方法在这个类。+ *+ * @ isgranting ("ROLE_ADMIN")+ * /类AdminController扩展AbstractController+ / * *+ *只对该控制器方法需要ROLE_ADMIN。+ *+ * @ isgranting ("ROLE_ADMIN")+ * /公共函数adminDashboard(): Response{//…}}

有关更多信息,请参见<一个href="//www.oldmanjams.com/doc/current/bundles/SensioFrameworkExtraBundle/index.html" class="reference external">FrameworkExtraBundle文欧宝体育电话档

注销

要启用注销,请激活注销防火墙下的配置参数:

  • YAML
  • XML
  • PHP
12 3 4 5 6 7 8 9 10 11 12
#配置/包/ security.yaml安全:#……防火墙:主要:#……注销:路径:app_logout#注销后重定向的位置#目标:app_any_route

接下来,你需要为这个URL创建一个路由(但不是控制器):

  • 注释
  • YAML
  • XML
  • PHP
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/ / src /控制器/ SecurityController.php名称空间应用程序控制器使用欧宝娱乐app下载地址FrameworkBundle控制器AbstractController使用欧宝娱乐app下载地址组件路由注释路线SecurityController扩展AbstractController/ * * *@Route(name = " /注销”“app_logout”方法={“获得”})* /公共函数注销()无效//控制器可以为空:它将永远不会被执行!异常“不要忘记在security.yaml中激活注销”);}}

就是这样!通过将用户发送到app_logout路线(即/注销Sy欧宝娱乐app下载地址mfony将取消当前用户的身份验证并重定向他们。

提示

需要更多地控制注销后发生的事情?添加一个success_handler关键在注销并将其指向实现的类的服务id<一个href="https://github.com/symfony/symfony/blob/4.4/src/Symfony/Component/Security/Http/Logout/LogoutSuccessHandlerInterface.php" class="reference external" title="LogoutSuccessHandlerInterface" rel="external noopener noreferrer" target="_blank">LogoutSuccessHandlerInterface

层次的角色

你可以通过创建角色层次结构来定义角色继承规则,而不是为每个用户分配许多角色:

  • YAML
  • XML
  • PHP
1 2 3 4 5 6 7
#配置/包/ security.yaml安全:#……role_hierarchy:ROLE_ADMIN:ROLE_USERROLE_SUPER_ADMIN:[ROLE_ADMIN,ROLE_ALLOWED_TO_SWITCH]

拥有ROLE_ADMIN角色也会有ROLE_USER的角色。和用户ROLE_SUPER_ADMIN,将自动拥有ROLE_ADMINROLE_ALLOWED_TO_SWITCH而且ROLE_USER(继承自ROLE_ADMIN).

为了使角色层次结构工作,不要尝试调用用户- >将getRoles ()手动。例如,在从<一个href="//www.oldmanjams.com/doc/4.4/controller.html" class="reference internal">基本控制器

1 2 3 4 5 6
getRoles()将不知道角色层次结构hasAccess= in_array (“ROLE_ADMIN”用户->将getRoles ());// GOOD -使用正常的安全方法hasAccess->isGranted (“ROLE_ADMIN”);->denyAccessUnlessGranted (“ROLE_ADMIN”);

请注意

role_hierarchy值是静态的——例如,您不能在数据库中存储角色层次结构。如果需要,可以创建一个自定义<一个href="//www.oldmanjams.com/doc/4.4/security/voters.html" class="reference internal">安全选民它在数据库中查找用户角色。

常见问题

我可以有多个防火墙吗?
是的!但这通常是不必要的。每个防火墙就像一个独立的安全系统。所以,除非你有非常不同的身份验证需求,一个防火墙通常可以很好地工作。与<一个href="//www.oldmanjams.com/doc/4.4/security/guard_authentication.html" class="reference internal">后卫的身份验证,你可以在同一防火墙下创建各种不同的认证方式(例如,表单登录,API密钥认证和LDAP)。
防火墙之间是否可以共享鉴权?
是的,但只是一些配置。如果您使用多个防火墙,并且针对其中一个防火墙进行身份验证,那么您就会这样做根据任何其他防火墙自动进行身份验证。不同的防火墙就像不同的安全系统。为此,您必须显式地指定相同的参数<一个href="//www.oldmanjams.com/doc/4.4/reference/configuration/security.html" class="reference internal">安全配置参考(SecurityBundle)针对不同的防火墙。然而,一个主防火墙通常足以满足大多数应用程序的需要。
在我的错误页上,安全性似乎不起作用
当路由完成时之前安全性,404错误页面不会被任何防火墙覆盖。这意味着您不能检查安全性,甚至不能访问这些页面上的用户对象。看到<一个href="//www.oldmanjams.com/doc/4.4/controller/error_pages.html" class="reference internal">如何自定义错误页面欲知详情。
我的身份验证似乎不工作:没有错误,但我从未登录
有时身份验证可能成功,但重定向后,由于加载用户从会议中。若要查看是否存在此问题,请检查日志文件(var / log / dev.log)以获取日志信息:
无法刷新令牌,因为用户已更改
如果你看到这个,有两个可能的原因。首先,从会话中加载User可能会出现问题。看到<一个href="//www.oldmanjams.com/doc/4.4/security/user_provider.html" class="reference internal">安全用户提供商.其次,如果自上次页面刷新以来数据库中的某些用户信息发生了更改,Symfony将出于安全原因故意注销该用户。欧宝娱乐app下载地址
此工作,包括代码示例,是根据<一个rel="license" href="https://creativecommons.org/licenses/by-sa/3.0/">创作共用BY-SA 3.0许可证。