全书目录

第三十七篇:Symfony 完全指南 —— 组件化政务城区宇宙

第十一章:Security,是整座城区的安检口、通行证系统和权限审核处

1 分钟 274 字 第 708 / 962 个阅读单元

Symfony 的 Security 体系很强,也正因为强,所以很多人一开始容易怕。

其实你把它当成三层就行:

text
1. 你是谁?
   = Authentication 认证

2. 你现在经过哪道安检?
   = Firewall 防火墙

3. 你对这份材料有没有这个动作权限?
   = Authorization 授权 / Voter

一个典型配置长这样:

yaml
security:
    password_hashers:
        Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'

    providers:
        app_user_provider:
            entity:
                class: App\Entity\User
                property: email

    firewalls:
        dev:
            pattern: ^/(_profiler|_wdt|assets|build)/
            security: false

        main:
            lazy: true
            provider: app_user_provider
            form_login: true
            logout: true

    access_control:
        - { path: ^/admin, roles: ROLE_REVIEWER }

这里最重要的不是记语法,而是理解它的城区含义:

  • provider:通行证档案从哪查
  • firewall:这次请求经过哪道安检门
  • access_control:某些区域先做粗粒度门禁

然后更细的权限判断,交给 Voter:

php
<?php

namespace App\Security\Voter;

use App\Entity\BusinessPermit;
use App\Entity\User;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;

final class PermitVoter extends Voter
{
    protected function supports(string $attribute, mixed $subject): bool
    {
        return in_array($attribute, ['PERMIT_VIEW', 'PERMIT_EDIT'], true)
            && $subject instanceof BusinessPermit;
    }

    protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool
    {
        $user = $token->getUser();

        if (!$user instanceof User) {
            return false;
        }

        if (in_array('ROLE_REVIEWER', $user->getRoles(), true)) {
            return true;
        }

        return $attribute === 'PERMIT_VIEW';
    }
}

这背后其实就是一个非常成熟的政务脑回路:

text
粗粒度门禁
= 哪些人能进哪栋楼

细粒度投票
= 对这份具体材料,他能看?能改?能批?

还要记住一条很实用的官方最佳实践:

如果不是确实存在两套完全不同的认证体系,尽量只有一个主 firewall。

多防火墙会让整座城区的通行逻辑变得很绕。