crocos / security-bundle
此包提供了一种通过注解配置安全性的方法
Requires
- php: >=5.4.0
- doctrine/common: >=2.2.0
- symfony/framework-bundle: >=2.1.0@dev
- symfony/http-foundation: >=2.1.0@dev
Requires (Dev)
- doctrine/orm: >=2.2.3
- facebook/php-sdk: dev-master
- phake/phake: >=2.0.0@dev
- phpunit/phpunit: >=3.7.0
- symfony/config: >=2.1.0@dev
- symfony/dependency-injection: >=2.1.0@dev
- symfony/doctrine-bridge: >=2.1.0@dev
- symfony/event-dispatcher: >=2.1.0@dev
- symfony/http-kernel: >=2.1.0@dev
This package is not auto-updated.
Last update: 2020-08-21 18:07:46 UTC
README
构建状态
概要
CrocosSecurityBundle 是一个用于Symfony的Bundle,旨在更简单地管理认证状态,是为了替换复杂的 SecurityBundle
而开发的。SecurityBundle
与之相比,有以下不同。
- 仅使用注解进行设置
- 登录、注销状态的切换由开发者明确执行
Symfony 2.0 用户
请使用 CrocosSecurityBundle
的 1.*
版本。
安装方法
使用Composer安装
在 composer.json
中添加 crocos/security-bundle。
{ "require": { "crocos/security-bundle": "dev-master" } }
app/AppKernel.php
注册 CrocosSecurityBundle
。
public function registerBundles() { $bundles = array( // ... new Crocos\SecurityBundle\CrocosSecurityBundle(), ); }
删除 Symfony\Bundle\SecurityBundle\SecurityBundle
的行。
app/config/config.yml
删除读取 security.yml
的行。
介绍
在控制器的方法或类上设置 Secure
注解和 SecureConfig
注解。
<?php use Crocos\SecurityBundle\Annotation\Secure; use Crocos\SecurityBundle\Annotation\SecureConfig; /** * @SecureConfig(forward="CrocosAppBundle:Security:login") */ abstract class AppController { } class SampleController extends AppController { /** * @Secure */ public function securedAction() { $user = $this->get('crocos_security.context')->getUser(); } } /** * @Secure */ class SecurityController extends AppController { public function login(Request $request) { $user = $this->findUser($request->request->get('username'), $request->request->get('password')); $this->get('crocos_security.context')->login($user); return $this->redirect('/'); } public function logout() { $this->get('crocos_security.context')->logout(); return $this->redirect('/login'); } }
注解
Secure 注解
添加了 Secure
注解的控制器需要认证。类上设置则应用于所有操作,方法上设置则仅针对指定的操作。
Secure
注解可设置以下属性。
disabled
- 类型:
boolean
- 默认:
false
设置为true表示无需认证。默认值是false,所以不传参数时 Secure
注解表示需要认证。
allow
- 类型:
array
- 默认:
[]
以数组形式设置所需的权限。
SecureConfig 注解
SecureConfig
注解用于进行认证相关设置。Secure
注解类似,可以设置在控制器的类或方法上。
SecureConfig
注解可设置以下属性。
domain
- 类型:
string
- 默认:
"secured"
当需要在同一项目中执行不同的认证处理时(例如,用户专用页面、管理员专用页面等),可以指定认证状态应适用的区域。
默认情况下使用会话来保持认证状态,但domain用作会话的命名空间。
auth
- 类型:
string
- 默认:
"session"
指定认证状态的管理方法。默认值是 "session"
,使用会话来管理认证状态。也可以设置自定义的管理方法。
转发
- 类型:
string
在未登录状态下访问需要认证的控制器时,将调用此处指定的控制器。可以指定控制器的名称(类::方法),或者使用Symfony的缩写形式(包名:控制器名:动作名)。如果没有指定forward
,则访问需要认证的控制器时会报错。
为了防止无限循环,即使认证是必需的,对通过forward
指定的控制器的访问也不会进行控制。
基本认证
- 类型:
string|array
启用BASIC认证。值可以是“用户名:密码”格式的字符串,也可以是包含该字符串的数组(= 多个用户)。
@SecureConfig(domain="secured", basic="user:pass")
认证域(realm)将基于domain
的值设置。"secured"
的情况下,将设置为“Secured Area”。
注释的读取
Secure
注释设置在类上时,将应用于所有动作。会读取父类的值,后读取的值将覆盖前面的值。
- 父类
- 子类
- 方法
如果没有指定disabled
属性,则会被覆盖为需要认证,但除非指定其他属性,否则不会被覆盖。只有当方法注释在读取时未指定时,才会设置默认值。
roleManager
- 类型:
string
- 默认:
"session"
指定权限的管理方法。默认值是"session"
,使用会话来管理认证状态。
指定"in_memory"
则权限只会在设置权限的进程内保持,进程结束时将被销毁。
httpsRequired
- 类型:
boolean
- 默认:
false
如果指定了true
,则在http
下访问指定的控制器时,将强制重定向到https
。
@SecureConfig(httpsRequired=true)
此外,在未设置SSL通信设置的开发服务器等环境中,可以在app/config/config_dev.yml
等文件中设置https_requiring: false
来禁用强制重定向到https。 (默认情况下是启用的)
crocos_security: https_requiring: false
示例代码
以下代码是使用注释进行认证的示例。
当使用
CrocosSecurityBundle
时,推荐为每个应用程序创建一个共享的控制器类,以便于设置。
基本示例
AppController
├── AccountController
│ ├── indexAction()
│ └── loginAction()
└── ProductController
├── buyAction()
└── showAction()
定义了继承自AppController
的ProductController
和AccountController
。由于ProductController
的buyAction
指定了Secure
注释,因此需要认证。由于AccountController
类指定了Secure
注释,因此所有动作都需要认证。但是,由于AppController
的SecureConfig
注释将loginAction
指定为转发,因此loginAction
始终不需要认证。
<?php namespace Crocos\AppBundle\Controller; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\HttpFoundation\Request; use Crocos\SecurityBundle\Annotation\Secure; use Crocos\SecurityBundle\Annotation\SecureConfig; /** * @SecureConfig(forward="CrocosAppBundle:Accont:login") */ abstract class AppController extends Controller { protected function getUser() { return $this->get('crocos_security.context')->getUser(); } } /** * @Route("/product") */ class ProductController extends AppController { /** * @Route("/{id}", requirements={"id" = "\d+"}) */ public function showAction($id) { // ... } /** * @Secure * @Route("/{id}/buy", requirements={"id" = "\d+"}) */ public function buyAction($id) { // ... } } /** * @Secure */ class AccountController extends AppController { /** * @Route("/account") */ public function indexAction() { // ... } /** * @Route("/login") * @Template */ public function loginAction(Request $request) { if ($request->getMethod() === 'POST') { $username = $request->request->get('username'); $password = $request->request->get('password'); $user = $this->get('doctrine')->getRepository('CrocosAppBundle:User') ->findUser($username, $password); $this->get('crocos_security.context')->login($user); return $this->redirect('/'); } return array(); } }
面向管理员页面的示例
创建管理员控制器时,可以这样指定domain
属性,以便与另一个认证域分开。AppController
指定了Secure
注释,因此所有控制器都需要认证。
<?php namespace Crocos\AppBundle\Controller\Admin; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\HttpFoundation\Request; use Crocos\SecurityBundle\Annotation\Secure; use Crocos\SecurityBundle\Annotation\SecureConfig; /** * @Secure * @SecureConfig(domain="admin", forward="CrocosAppBundle:Admin\Accont:login") */ abstract class AppController extends Controller { protected function getUser() { return $this->get('crocos_security.context')->getUser(); } } /** * @Route("/admin") */ class AccountController extends AppController { /** * @Route("/login") */ public function loginAction(Request $request) { // ... } }
设置Basic认证
要设置Basic认证,请将SecureConfig
注释中的basic
属性指定。在此示例中,用户名为"admin"
,密码为"password"
。
<?php namespace Crocos\AppBundle\Controller\Admin; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\HttpFoundation\Request; use Crocos\SecurityBundle\Annotation\Secure; use Crocos\SecurityBundle\Annotation\SecureConfig; /** * @SecureConfig(domain="admin", basic="admin:password") */ abstract class AppController extends Controller { }
此外,Basic认证的设置与Secure
注释的设置无关。如果设置了basic
属性,则认证域内的所有动作都将执行Basic认证。如果想要部分禁用Basic认证,可以将basic
属性的值设置为false
。当然,也可以通过设置如auth
或forward
属性等方式在PHP侧进行认证设置。
此外,也可以用参数形式指定用户名/密码。
@SecureConfig(domain="admin", basic="%app.basic_auth%")
app/config/parameters.yml
:
parameters: app.basic_auth: admin:password
SecurityContext
与认证相关的状态由服务容器中注册的键为crocos_security.context
的Crocos\SecurityBundle\Security\SecurityContext
对象保持。有关实际处理内容的说明,请参阅下面的Auth Logic。
登录
要执行登录,请将用户信息传递给login()
方法。
$user = $userRepository->findUser('Katsuhiro Ogawa'); $this->get('crocos_security.context')->login($user);
登录状态的确认
可以使用isAuthenticated()
方法来确认登录状态。
if ($this->get('crocos_security.context')->isAuthenticated()) { echo 'ログインしています'; }
获取登录用户
可以使用getUser()
方法来获取登录用户。如果未登录,则返回null。
$user = $this->get('crocos_security.context')->getUser();
注销
可以通过logout()
方法进行注销。
$this->get('crocos_security.context')->logout(); $this->get('crocos_security.context')->getUser(); // => null $this->get('crocos_security.context')->isAuthenticated(); // => false
Auth Logic
Auth Logic 是切换认证状态管理方法的一种机制。Secure
注释的 auth
与之对应。标准情况下,使用会话来管理认证状态的是 SessionAuth
(auth="session"
),还有考虑到在会话中存储实体的情况的 SessionEntityAuth
。还可以扩展现有的 Auth Logic 或创建自定义的 Auth Logic。
SessionAuth
@SecureConfig(auth="session")
SessionAuth
是使用会话来管理认证状态的机制。
SessionEntityAuth
@SecureConfig(auth="session.entity")
SessionEntityAuth
是为登录用户使用实体而设计的,基本上与 SessionAuth
相同。SessionAuth
使用时,登录用户信息会被序列化并存储在会话中。如果用户信息是对象,则对象会被序列化并保存。SessionEntityAuth
使用时,只会将类名和ID存储到会话中,每次访问时都会从存储库中获取实体。
在使用 SessionEntityAuth
时,登录目标实体必须实现 getId()
方法。这个值在从会话恢复实体时被传递给存储库的 find()
方法。此外,如果需要验证登录中用户的有效性,可以通过在实体中实现 isEnabled()
方法来在获取实体后进行有效性验证。如果 isEnabled()
为 false
,即使已登录也会被注销。
自定义Auth Logic
要创建自定义 Auth Logic,首先需要创建一个实现了 Crocos\SecurityBundle\Security\AuthLogic\AuthLogicInterface
接口的类。Auth Logic 需要定义以下 5 个方法。
setDomain($domain)
login($user)
logout()
isAuthenticated()
getUser()
除了 setDomain()
方法外,其他方法都是通过委派的形式从 SecurityContext
类中调用的。setDomain()
方法将使用注解读取的 domain
值传递。
自定义Auth Logic的注册
创建 Auth Logic 后,需要将其注册到 DI 容器中。此时,通过附加 crocos_security.auth_logic
标签,可以将其注册到 CrocosSecurityBundle 中。在注解中指定在 alias
中记录的值。
services: myapp.security.my_auth: class: Crocos\AppBundle\Security\MyAuth tags: - { name: crocos_security.auth_logic, alias: my_auth }
调用上述 Auth Logic 的方式如下。
/** * @SecureConfig(auth="my_auth") */ class AppController { }
AuthException
如果需要在任意位置转到登录页面,则抛出 Crocos\SecurityBundle\Exception\AuthException
对象。另外,可以在 AuthException
构造函数的第二个参数中指定 attributes
数组,并在转到登录页面时将其作为路由参数传递。
<?php namespace Crocos\AppBundle\Controller; use Crocos\SecurityBundle\Annotation\Secure; use Crocos\SecurityBundle\Annotation\SecureConfig; use Crocos\SecurityBundle\Exception\AuthException; /** * @SecureConfig(forward="CrocosAppBundle:Demo:login") */ class AppController { } class DemoController extends AppController { /** * @Secure */ public function someAction($id) { if ($this->hasSomeError()) { throw new AuthException('Login required', array('id' => $id)); } } public function loginAction($id = null) { // do login } }
Twig集成
读取 CrocosSecurityBundle 后,在 Twig 模板内会启用 _security
变量。_security
变量持有 SecurityContext
对象的引用。可以使用它在模板内进行条件分支等操作。
{% if _security.isAuthenticated %} <p>Logged in as {{ _security.user }}</p> {% endif %}