如何在Silex框架中使用SecurityServiceProvider实现用户认证?
Hey there, I get it—wrapping your head around Silex's SecurityServiceProvider can feel pretty overwhelming when you're just starting out with the framework. Let’s break this down step by step, using your existing project structure as a base.
First, make sure your composer.json includes the required security and database components. If you haven’t already, add these entries to the require section:
{ "require": { "silex/silex": "^2.0", "silex/security-provider": "^2.0", "doctrine/dbal": "^2.9", "symfony/security-csrf": "^4.4", "silex/twig-provider": "^2.0" } }
Run composer update to install the new dependencies.
App.php This is the core part—we’ll register the security provider, set up the firewall, connect to your MySQL database, and define how users are authenticated.
Update your App.php with this configuration:
<?php require_once __DIR__.'/vendor/autoload.php'; $app = new Silex\Application(); $app['debug'] = true; // 1. Register Doctrine for MySQL connection $app->register(new Silex\Provider\DoctrineServiceProvider(), [ 'db.options' => [ 'driver' => 'pdo_mysql', 'host' => 'localhost', 'dbname' => 'your_database_name', 'user' => 'your_db_user', 'password' => 'your_db_password', 'charset' => 'utf8', ], ]); // 2. Register Twig for rendering templates $app->register(new Silex\Provider\TwigServiceProvider(), [ 'twig.path' => __DIR__.'/views', ]); // 3. Register and configure SecurityServiceProvider $app->register(new Silex\Provider\SecurityServiceProvider(), [ 'security.firewalls' => [ 'main' => [ 'pattern' => '^/', 'anonymous' => true, // Allow unauthenticated access to login page 'form' => [ 'login_path' => '/', // Root path is your login page 'check_path' => '/login_check', // Form submits to this route (handled by Security) 'csrf_token_generator' => 'security.csrf.token_manager', // Enable CSRF protection ], 'logout' => [ 'logout_path' => '/logout', 'target_url' => '/', ], 'users' => function ($app) { // Pull user data from your MySQL `users` table return new Symfony\Component\Security\Core\User\EntityUserProvider( $app['db'], 'users', // Your users table name 'username', // Column storing the username 'password', // Column storing the hashed password 'role' // Column storing the user role (e.g., ROLE_USER, ROLE_ADMIN) ); }, ], ], // Password encoder (use BCrypt for secure hashing) 'security.encoder_factory' => $app->factory(function ($app) { return new Symfony\Component\Security\Core\Encoder\EncoderFactory([ Symfony\Component\Security\Core\User\User::class => new Symfony\Component\Security\Core\Encoder\BCryptPasswordEncoder(12), ]); }), // Optional: Role hierarchy (let admins access regular user pages) 'security.role_hierarchy' => [ 'ROLE_ADMIN' => ['ROLE_USER'], 'ROLE_JURY' => ['ROLE_USER'], ], ]); // 4. Customize login success redirect (based on user role) $app['security.authentication.success_handler'] = $app->extend('security.authentication.success_handler', function ($handler, $app) { $customHandler = new class($handler, $app['security.http_utils']) extends Symfony\Component\Security\Http\Authentication\DefaultAuthenticationSuccessHandler { public function onAuthenticationSuccess(\Symfony\Component\HttpFoundation\Request $request, \Symfony\Component\Security\Core\Authentication\Token\TokenInterface $token) { $user = $token->getUser(); $roles = $user->getRoles(); // Redirect to role-specific page if (in_array('ROLE_ADMIN', $roles)) { return new \Symfony\Component\HttpFoundation\RedirectResponse('/admin'); } elseif (in_array('ROLE_JURY', $roles)) { return new \Symfony\Component\HttpFoundation\RedirectResponse('/jury'); } else { return new \Symfony\Component\HttpFoundation\RedirectResponse('/user'); } } }; return $customHandler; }); return $app;
Controllers.php Define your public and protected routes, with role-based access controls:
<?php // Login page (root path) $app->get('/', function () use ($app) { return $app['twig']->render('login.twig', [ 'error' => $app['security.last_error']($app['request']), 'last_username' => $app['session']->get('_security.last_username'), ]); })->bind('login'); // Login submission route (handled automatically by Security) $app->post('/login_check', function () { // This code won't run—Security processes the login here }); // Regular user dashboard (requires ROLE_USER) $app->get('/user', function () use ($app) { $user = $app['security.token_storage']->getToken()->getUser(); return $app['twig']->render('user.twig', ['username' => $user->getUsername()]); })->bind('user_home')->secure('ROLE_USER'); // Admin dashboard (requires ROLE_ADMIN) $app->get('/admin', function () use ($app) { return $app['twig']->render('admin.twig'); })->bind('admin_home')->secure('ROLE_ADMIN'); // Jury dashboard (requires ROLE_JURY) $app->get('/jury', function () use ($app) { return $app['twig']->render('jury.twig'); })->bind('jury_home')->secure('ROLE_JURY'); // Logout route (handled automatically by Security) $app->get('/logout', function () { // This code won't run—Security processes logout here });
Create a views folder in your project root, then add these files:
login.twig (Login form)
<!DOCTYPE html> <html> <head> <title>Login</title> </head> <body> {% if error %} <div style="color: red;">{{ error.messageKey|trans(error.messageData, 'security') }}</div> {% endif %} <form action="{{ path('login_check') }}" method="post"> <div> <label>Username:</label> <input type="text" name="_username" value="{{ last_username }}" required> </div> <div> <label>Password:</label> <input type="password" name="_password" required> </div> <!-- CSRF Token (required for security) --> <input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}"> <button type="submit">Login</button> </form> </body> </html>
Example user.twig (Regular user dashboard)
<!DOCTYPE html> <html> <head> <title>User Dashboard</title> </head> <body> <h1>Welcome, {{ username }}!</h1> <p>This is your regular user dashboard.</p> <a href="{{ path('logout') }}">Logout</a> </body> </html>
Repeat similar templates for admin.twig and jury.twig.
- Password Storage: Ensure your MySQL
userstable stores hashed passwords (not plain text). Generate hashes with this quick script:<?php require_once 'vendor/autoload.php'; $encoder = new Symfony\Component\Security\Core\Encoder\BCryptPasswordEncoder(12); echo $encoder->encodePassword('your_plain_text_password', null); - User Table Structure: Your
userstable should have at least these columns:id(INT, primary key)username(VARCHAR, unique)password(VARCHAR, min length 60 for BCrypt)role(VARCHAR, e.g., 'ROLE_USER', 'ROLE_ADMIN', 'ROLE_JURY')
内容的提问来源于stack exchange,提问作者Victor

