安全基础 #

一、安全组件概述 #

1.1 安全组件功能 #

text
┌─────────────────────────────────────────────────────┐
│                  安全组件功能                        │
├─────────────────────────────────────────────────────┤
│  • 认证:验证用户身份                                │
│  • 授权:控制访问权限                                │
│  • 防火墙:保护应用安全                              │
│  • CSRF保护:防止跨站请求伪造                        │
│  • 密码加密:安全存储密码                            │
│  • 会话管理:安全会话处理                            │
└─────────────────────────────────────────────────────┘

1.2 安装安全组件 #

bash
# 安装安全组件
composer require security

二、安全配置 #

2.1 基本配置 #

yaml
# config/packages/security.yaml
security:
    providers:
        app_user_provider:
            entity:
                class: App\Entity\User
                property: email

    password_hashers:
        App\Entity\User:
            algorithm: auto

    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false

        main:
            lazy: true
            provider: app_user_provider
            form_login:
                login_path: app_login
                check_path: app_login
            logout:
                path: app_logout

    access_control:
        - { path: ^/admin, roles: ROLE_ADMIN }
        - { path: ^/profile, roles: ROLE_USER }

2.2 用户提供者 #

yaml
# config/packages/security.yaml
security:
    providers:
        # 实体提供者
        app_user_provider:
            entity:
                class: App\Entity\User
                property: email

        # 内存提供者
        in_memory:
            memory:
                users:
                    admin:
                        password: $2y$13$...
                        roles: ROLE_ADMIN

2.3 密码加密器 #

yaml
# config/packages/security.yaml
security:
    password_hashers:
        # 自动选择最佳算法
        App\Entity\User:
            algorithm: auto

        # 指定算法
        App\Entity\LegacyUser:
            algorithm: bcrypt
            cost: 12

三、用户实体 #

3.1 创建用户实体 #

bash
# 使用Maker创建用户实体
php bin/console make:user

# 输出
created: src/Entity/User.php
created: src/Repository/UserRepository.php
updated: config/packages/security.yaml

3.2 用户实体定义 #

php
<?php

namespace App\Entity;

use App\Repository\UserRepository;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
use Symfony\Component\Security\Core\User\UserInterface;

#[ORM\Entity(repositoryClass: UserRepository::class)]
class User implements UserInterface, PasswordAuthenticatedUserInterface
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\Column(length: 180, unique: true)]
    private ?string $email = null;

    #[ORM\Column]
    private array $roles = [];

    #[ORM\Column]
    private ?string $password = null;

    public function getId(): ?int
    {
        return $this->id;
    }

    public function getEmail(): ?string
    {
        return $this->email;
    }

    public function setEmail(string $email): static
    {
        $this->email = $email;
        return $this;
    }

    public function getUserIdentifier(): string
    {
        return (string) $this->email;
    }

    public function getRoles(): array
    {
        $roles = $this->roles;
        $roles[] = 'ROLE_USER';
        return array_unique($roles);
    }

    public function setRoles(array $roles): static
    {
        $this->roles = $roles;
        return $this;
    }

    public function getPassword(): string
    {
        return $this->password;
    }

    public function setPassword(string $password): static
    {
        $this->password = $password;
        return $this;
    }

    public function eraseCredentials(): void
    {
    }
}

四、防火墙配置 #

4.1 防火墙基础 #

yaml
# config/packages/security.yaml
security:
    firewalls:
        # 开发环境防火墙
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false

        # API防火墙
        api:
            pattern: ^/api/
            stateless: true
            http_basic: true

        # 主防火墙
        main:
            pattern: ^/
            lazy: true
            provider: app_user_provider
            form_login:
                login_path: app_login
                check_path: app_login
                default_target_path: app_home
            logout:
                path: app_logout
                target: app_home
            remember_me:
                secret: '%kernel.secret%'
                lifetime: 604800

4.2 防火墙选项 #

选项 说明
pattern URL匹配模式
provider 用户提供者
lazy 延迟加载用户
stateless 无状态模式
form_login 表单登录
http_basic HTTP基本认证
logout 登出配置
remember_me 记住我功能

五、访问控制 #

5.1 基本访问控制 #

yaml
# config/packages/security.yaml
security:
    access_control:
        - { path: ^/admin, roles: ROLE_ADMIN }
        - { path: ^/profile, roles: ROLE_USER }
        - { path: ^/api, roles: PUBLIC_ACCESS }
        - { path: ^/login, roles: PUBLIC_ACCESS }
        - { path: ^/register, roles: PUBLIC_ACCESS }

5.2 条件访问控制 #

yaml
# config/packages/security.yaml
security:
    access_control:
        - { path: ^/admin, roles: ROLE_ADMIN, ips: [127.0.0.1, 192.168.0.0/16] }
        - { path: ^/api/admin, roles: ROLE_API_ADMIN, methods: [POST, PUT, DELETE] }
        - { path: ^/secure, roles: ROLE_USER, host: secure\.example\.com }

5.3 访问控制选项 #

选项 说明
path URL路径模式
roles 所需角色
methods HTTP方法限制
ips IP地址限制
host 主机名限制
allow_if 表达式条件

六、角色管理 #

6.1 角色层次 #

yaml
# config/packages/security.yaml
security:
    role_hierarchy:
        ROLE_ADMIN: [ROLE_USER, ROLE_EDITOR]
        ROLE_SUPER_ADMIN: [ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]

6.2 检查角色 #

php
<?php

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Security\Http\Attribute\IsGranted;

class AdminController extends AbstractController
{
    #[Route('/admin', name: 'app_admin')]
    #[IsGranted('ROLE_ADMIN')]
    public function index(): Response
    {
        return $this->render('admin/index.html.twig');
    }

    #[Route('/admin/users', name: 'app_admin_users')]
    public function users(): Response
    {
        $this->denyAccessUnlessGranted('ROLE_ADMIN');
        
        return $this->render('admin/users.html.twig');
    }
}

6.3 模板中检查角色 #

twig
{# 检查角色 #}
{% if is_granted('ROLE_ADMIN') %}
    <a href="{{ path('app_admin') }}">管理后台</a>
{% endif %}

{% if is_granted('ROLE_USER') %}
    <p>欢迎, {{ app.user.name }}</p>
{% endif %}

七、CSRF保护 #

7.1 CSRF配置 #

yaml
# config/packages/framework.yaml
framework:
    csrf_protection: true

7.2 表单CSRF保护 #

php
<?php

use Symfony\Component\Security\Csrf\CsrfToken;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;

class FormController extends AbstractController
{
    public function submit(Request $request, CsrfTokenManagerInterface $csrfTokenManager): Response
    {
        $token = new CsrfToken('form_id', $request->request->get('_token'));
        
        if (!$csrfTokenManager->isTokenValid($token)) {
            throw new \Exception('CSRF token is invalid');
        }
        
        // 处理表单
    }
}

7.3 模板中CSRF令牌 #

twig
<form method="post">
    <input type="hidden" name="_token" value="{{ csrf_token('form_id') }}">
    
    <button type="submit">提交</button>
</form>

八、密码处理 #

8.1 密码加密 #

php
<?php

use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;

class RegistrationController extends AbstractController
{
    public function register(
        Request $request,
        UserPasswordHasherInterface $passwordHasher,
        EntityManagerInterface $entityManager
    ): Response {
        $user = new User();
        $form = $this->createForm(RegistrationFormType::class, $user);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $plainPassword = $form->get('plainPassword')->getData();
            
            $hashedPassword = $passwordHasher->hashPassword(
                $user,
                $plainPassword
            );
            
            $user->setPassword($hashedPassword);
            
            $entityManager->persist($user);
            $entityManager->flush();

            return $this->redirectToRoute('app_home');
        }

        return $this->render('registration/register.html.twig', [
            'registrationForm' => $form,
        ]);
    }
}

8.2 密码验证 #

php
<?php

class LoginController extends AbstractController
{
    public function login(AuthenticationUtils $authenticationUtils): Response
    {
        $error = $authenticationUtils->getLastAuthenticationError();
        $lastUsername = $authenticationUtils->getLastUsername();

        return $this->render('security/login.html.twig', [
            'last_username' => $lastUsername,
            'error' => $error,
        ]);
    }
}

九、安全最佳实践 #

9.1 安全建议 #

text
安全建议:
├── 使用HTTPS
├── 强密码策略
├── 密码加密存储
├── 启用CSRF保护
├── 限制登录尝试
├── 使用安全Cookie
├── 定期更新依赖
└── 安全审计日志

9.2 安全检查 #

bash
# 检查安全漏洞
symfony security:check

# 检查依赖漏洞
composer audit

十、总结 #

本章学习了:

  • 安全组件概述
  • 安全配置
  • 用户实体定义
  • 防火墙配置
  • 访问控制
  • 角色管理
  • CSRF保护
  • 密码处理

下一章将学习 用户认证

最后更新:2026-03-28