弱化security.context服务 

这是symfony2.6的主要改进点之一。好在这并不会影响你的代码,因为它维持了向后兼容(译注:3.0都会取消)。多数情况下,考虑到为将来的symfony版本做好准备,你应该学习操作security的新方法。

做出如此改变的原因,是因为当你注入SecurityContext到其他服务中时,特别是那些跟doctrine有关的,你可能会陷入“循环引用(circular reference)”进而导致异常。

经过sf社区的讨论,大家一致认为SecurityContext在仅为取出简单的Token/User时存在过度依赖。这就是为什么从2.6起,security.context服务被弱化并被分为两个全新服务的原因:security.authorization_checkersecurity.token_storage.

由于100%向下兼容,你毋须更新现有程序代码。不过,万一你需要这样做,进行如下微小变化:

1
2
3
4
5
6
7
8
9
// Symfony 2.5
$user = $this->get('security.context')->getToken()->getUser();
// Symfony 2.6
$user = $this->get('security.token_storage')->getToken()->getUser();
 
// Symfony 2.5
if (false === $this->get('security.context')->isGranted('ROLE_ADMIN')) { ... }
// Symfony 2.6
if (false === $this->get('security.authorization_checker')->isGranted('ROLE_ADMIN')) { ... }

作为这项改变的附加奖励,则是对security相关常量的简化,大幅方便了记忆:

1
2
3
4
5
6
7
// Symfony 2.5
use Symfony\Component\Security\Core\SecurityContextInterface;
if ($security->has(SecurityContextInterface::AUTHENTICATION_ERROR)) { ... }
 
// Symfony 2.6
use Symfony\Component\Security\Core\Security;
if ($security->has(Security::AUTHENTICATION_ERROR)) { ... }

最后,此一改进点同时也弱化了app.security这个Twig全局模板变量。你应该使用app.user变量以及is_granted()函数。

用于简化密码加密的新服务 

作为一个DX开发体验建议的反馈,symfony2.6引入了全新的security.password_encoder服务,用于给密码加密:

1
2
3
4
5
6
7
8
9
10
// Symfony 2.5
$user = new Acme\UserBundle\Entity\User();
$factory = $this->container->get('security.encoder_factory');
$encoder = $factory->getEncoder($user);
$password = $encoder->encodePassword($plainTextPassword, $user->getSalt());
 
// Symfony 2.6
$user = new Acme\UserBundle\Entity\User();
$encoder = $this->container->get('security.password_encoder');
$password = $encoder->encodePassword($user, $plainTextPassword);

为security firewall添加了基于REMOTE_USER的监听 

某些Apache服务模块(auth_kerb, auth_cas等),通过被称为REMOTE_USER的环境变量来提供username。因此,Symfony 2.6引入了一个新的验证监听,用于此变量。

1
2
3
4
5
6
7
# app/config/security.yml
security:
    firewalls:
        secured_area:
            pattern: ^/
            remote_user:
                provider: your_user_provider

添加了一个security error helper服务 

自定义一个登陆表单,这在symfony中是相当容易的,但代码层面却相对冗余一些:

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
// Symfony 2.5
public function loginAction(Request $request)
{
    $session = $request->getSession();
 
    if ($request->attributes->has(SecurityContextInterface::AUTHENTICATION_ERROR)) {
        $error = $request->attributes->get(
            SecurityContextInterface::AUTHENTICATION_ERROR
        );
    } elseif (null !== $session && $session->has(SecurityContextInterface::AUTHENTICATION_ERROR)) {
        $error = $session->get(SecurityContextInterface::AUTHENTICATION_ERROR);
        $session->remove(SecurityContextInterface::AUTHENTICATION_ERROR);
    } else {
        $error = '';
    }
 
    $lastUsername = (null === $session) ? '' : $session->get(SecurityContextInterface::LAST_USERNAME);
 
    return $this->render(
        'AcmeSecurityBundle:Security:login.html.twig',
        array(
            'last_username' => $lastUsername,
            'error'         => $error,
        )
    );
}

那么作为对DX开发体验#11147的响应,我们决定在Symfony 2.6中引入一个全新的helper,它令人惊异地把表单action中的代码戏剧化地减少到了如下程度:

1
2
3
4
5
6
7
8
9
10
// Symfony 2.6
public function loginAction()
{
    $helper = $this->get('security.authentication_utils');
 
    return $this->render('AcmeSecurityBundle:Security:login.html.twig', array(
        'last_username' => $helper->getLastUsername(),
        'error'         => $helper->getLastAuthenticationError(),
    ));
}