Symfony Security
認証ライブラリ
Symfony Security
概要
Symfony Securityは、Symfonyフレームワークの核となるセキュリティコンポーネントです。認証(Authentication)と認可(Authorization)の包括的なシステムを提供し、ファイアウォール、認証プロバイダー、アクセス制御などの機能を統合したセキュアなWebアプリケーション開発を可能にします。
詳細
Symfony Securityは、モジュラー設計により柔軟で拡張可能なセキュリティ機能を提供します。ファイアウォールシステムを中心とした認証メカニズム、ロールベースアクセス制御(RBAC)、CSRF保護、二要素認証サポートなど、企業レベルのセキュリティ要件に対応します。
主要コンポーネント
- Firewall(ファイアウォール): リクエストフィルタリングと認証機能
- Authenticator: 認証方式を定義するミドルウェア
- User Provider: ユーザー情報の取得とロード
- Access Control: URL ベースの認可ルール
- Guard Middleware: 認証チェックの強制実行
認証方式
- Form Login: フォームベース認証
- HTTP Basic: Basic認証
- Bearer Token: JWT、APIトークン認証
- JSON Login: JSON形式のログイン
- X.509: クライアント証明書認証
- Remote User: 外部認証システム連携
高度なセキュリティ機能
- 2FA(二要素認証): TOTP、SMS認証
- Remember Me: 永続的なログイン機能
- CSRF Protection: クロスサイトリクエストフォージェリ対策
- Security Voters: カスタム認可ロジック
メリット・デメリット
メリット
- 包括的セキュリティ: 認証から認可まで完全対応
- 柔軟な設定: YAML、XML、PHPでの詳細設定
- 多様な認証方式: 豊富な認証オプション
- エンタープライズ対応: 大規模システムに適用可能
- コミュニティサポート: 豊富なドキュメントとサポート
- モジュラー設計: 必要な機能のみ選択使用可能
デメリット
- 学習コスト: 設定が複雑で習得に時間を要する
- パフォーマンス: 多機能ゆえの処理オーバーヘッド
- Symfony依存: Symfonyフレームワーク専用
- 設定の複雑さ: 細かい設定が必要で初期構築が困難
参考ページ
- Symfony Security Documentation - 公式ドキュメント
- Symfony Security Configuration Reference - 設定リファレンス
- Symfony Security Best Practices - セキュリティベストプラクティス
書き方の例
基本設定(security.yaml)
# config/packages/security.yaml
security:
enable_authenticator_manager: true
password_hashers:
App\Entity\User:
algorithm: auto
providers:
app_user_provider:
entity:
class: App\Entity\User
property: email
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 }
カスタム認証プロバイダー
<?php
// src/Security/ApiKeyAuthenticator.php
namespace App\Security;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
class ApiKeyAuthenticator extends AbstractAuthenticator
{
public function supports(Request $request): ?bool
{
return $request->headers->has('X-API-TOKEN');
}
public function authenticate(Request $request): Passport
{
$apiToken = $request->headers->get('X-API-TOKEN');
if (null === $apiToken) {
throw new CustomUserMessageAuthenticationException('No API token provided');
}
return new SelfValidatingPassport(new UserBadge($apiToken));
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
{
return null;
}
public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
{
$data = [
'message' => strtr($exception->getMessageKey(), $exception->getMessageData())
];
return new JsonResponse($data, Response::HTTP_UNAUTHORIZED);
}
}
Bearer トークン認証設定
# config/packages/security.yaml
security:
firewalls:
api:
pattern: ^/api/
stateless: true
bearer_token:
token_handler: App\Security\AccessTokenHandler
main:
lazy: true
form_login:
login_path: app_login
check_path: app_login
アクセストークンハンドラー
<?php
// src/Security/AccessTokenHandler.php
namespace App\Security;
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
use Symfony\Component\Security\Http\AccessToken\AccessTokenHandlerInterface;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
class AccessTokenHandler implements AccessTokenHandlerInterface
{
public function getUserBadgeFrom(string $accessToken): UserBadge
{
// トークンの検証とユーザー識別
if (!$this->isValidToken($accessToken)) {
throw new BadCredentialsException('Invalid credentials.');
}
$userIdentifier = $this->getUserIdentifierFromToken($accessToken);
return new UserBadge($userIdentifier);
}
private function isValidToken(string $token): bool
{
// トークン検証ロジック
return hash('sha256', 'your-secret') === $token;
}
private function getUserIdentifierFromToken(string $token): string
{
// トークンからユーザー識別子を取得
return '[email protected]';
}
}
複数認証方式の組み合わせ
# config/packages/security.yaml
security:
firewalls:
main:
lazy: true
provider: app_user_provider
# 複数の認証方式を同時に有効化
form_login:
login_path: app_login
check_path: app_login
custom_authenticators:
- App\Security\SocialConnectAuthenticator
- App\Security\ApiKeyAuthenticator
# エントリーポイントを明示的に指定
entry_point: form_login
Guard ミドルウェア使用例
<?php
// src/Controller/AdminController.php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
class AdminController extends AbstractController
{
#[Route('/admin', name: 'admin_dashboard')]
#[IsGranted('ROLE_ADMIN')]
public function dashboard(): Response
{
// 管理者のみアクセス可能
return $this->render('admin/dashboard.html.twig');
}
#[Route('/admin/users', name: 'admin_users')]
public function users(): Response
{
// プログラムでロール確認
$this->denyAccessUnlessGranted('ROLE_ADMIN');
return $this->render('admin/users.html.twig');
}
}
CSRF保護の実装
<?php
// src/Form/LoginType.php
namespace App\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class LoginType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('email', TextType::class)
->add('password', PasswordType::class)
->add('login', SubmitType::class);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'csrf_protection' => true,
'csrf_field_name' => '_token',
'csrf_token_id' => 'authenticate',
]);
}
}
ユーザー エンティティ例
<?php
// src/Entity/User.php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
use Symfony\Component\Security\Core\User\UserInterface;
#[ORM\Entity]
class User implements UserInterface, PasswordAuthenticatedUserInterface
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: 'integer')]
private int $id;
#[ORM\Column(type: 'string', length: 180, unique: true)]
private string $email;
#[ORM\Column(type: 'json')]
private array $roles = [];
#[ORM\Column(type: 'string')]
private string $password;
public function getUserIdentifier(): string
{
return $this->email;
}
public function getRoles(): array
{
$roles = $this->roles;
$roles[] = 'ROLE_USER';
return array_unique($roles);
}
public function getPassword(): string
{
return $this->password;
}
public function eraseCredentials(): void
{
// 一時的な機密データをクリア
}
}