You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Symfony 6(EasyAdmin 4)中实现用户账号封禁?

Symfony 6 + EasyAdmin 4 实现用户账号封禁功能

问题背景

我在Symfony 6和EasyAdmin 4环境下想实现网站用户账号封禁功能,一开始尝试创建ROLE_BLOCKED角色,打算在控制器里用类似IsDenied的函数限制访问,但发现Symfony 6里找不到这个函数。

相关代码

LoginAuthenticator.php

class LoginAuthenticator extends AbstractLoginFormAuthenticator
{
    use TargetPathTrait;

    public const LOGIN_ROUTE = 'app_login';

    public function __construct(private UrlGeneratorInterface $urlGenerator)
    {
    }

    public function authenticate(Request $request): Passport
    {
        $email = $request->request->get('email', '');

        $request->getSession()->set(Security::LAST_USERNAME, $email);

        return new Passport(
            new UserBadge($email),
            new PasswordCredentials($request->request->get('password', '')),
            [
                new CsrfTokenBadge('authenticate', $request->request->get('_csrf_token')),
            ]
        );
    }

    public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
    {
        if ($targetPath = $this->getTargetPath($request->getSession(), $firewallName)) {
            return new RedirectResponse($targetPath);
        }

        // For example:
        // return new RedirectResponse($this->urlGenerator->generate('some_route'));
        throw new \Exception('TODO: provide a valid redirect inside '.__FILE__);
    }

    protected function getLoginUrl(Request $request): string
    {
        return $this->urlGenerator->generate(self::LOGIN_ROUTE);
    }
}

security.yaml

# https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords
    password_hashers:
        Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
    # https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider
    providers:
        # used to reload user from session & other features (e.g. switch_user)
        app_user_provider:
            entity:
                class: App\Entity\User
                property: email
        # used to reload user from session & other features (e.g. switch_user)
    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        main:
            lazy: true
            provider: app_user_provider
            custom_authenticator: App\Security\RegisterAuthenticator
            logout:
                path: app_logout
                # where to redirect after logout
                # target: app_any_route

            # activate different ways to authenticate
            # https://symfony.com/doc/current/security.html#the-firewall

            # https://symfony.com/doc/current/security/impersonating_user.html
            # switch_user: true

    role_hierarchy:
            ROLE_ADMIN:   ROLE_USER
            ROLE_ARTIST:  ROLE_USER

    # Easy way to control access for large sections of your site
    # Note: Only the *first* access control that matches will be used
    access_control:
         - { path: ^/admin, roles: ROLE_ADMIN }
         - { path: ^/profile, roles: ROLE_USER }

when@test:
    security:
        password_hashers:
            # By default, password hashers are resource intensive and take time. This is
            # important to generate secure password hashes. In tests however, secure hashes
            # are not important, waste resources and increase test times. The following
            # reduces the work factor to the lowest possible values.
            Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface:
                algorithm: auto
                cost: 4 # Lowest possible value for bcrypt
                time_cost: 3 # Lowest possible value for argon
                memory_cost: 10 # Lowest possible value for argon

解决方案:使用UserChecker类

通过自定义UserChecker类可以完美解决账号封禁的问题,具体步骤如下:

  1. 给User实体添加封禁状态字段
    先在App\Entity\User中添加isBlocked布尔字段,用于标记用户是否被封禁:

    // src/Entity/User.php
    use Doctrine\ORM\Mapping as ORM;
    
    class User implements UserInterface, PasswordAuthenticatedUserInterface
    {
        // ... 已有字段
    
        #[ORM\Column(type: 'boolean')]
        private bool $isBlocked = false;
    
        // 生成对应的getter和setter
        public function isBlocked(): bool
        {
            return $this->isBlocked;
        }
    
        public function setIsBlocked(bool $isBlocked): self
        {
            $this->isBlocked = $isBlocked;
            return $this;
        }
    
        // ... 已有方法
    }
    

    执行数据库迁移命令更新表结构:

    php bin/console make:migration
    php bin/console doctrine:migrations:migrate
    
  2. 创建自定义UserChecker类
    在src/Security目录下新建UserChecker.php:

    // src/Security/UserChecker.php
    use Symfony\Component\Security\Core\User\UserCheckerInterface;
    use Symfony\Component\Security\Core\User\UserInterface;
    use Symfony\Component\Security\Core\Exception\LockedException;
    
    class UserChecker implements UserCheckerInterface
    {
        public function checkPreAuth(UserInterface $user): void
        {
            if (!$user instanceof \App\Entity\User) {
                return;
            }
    
            // 校验用户是否被封禁
            if ($user->isBlocked()) {
                throw new LockedException('你的账号已被封禁,请联系管理员。');
            }
        }
    
        public function checkPostAuth(UserInterface $user): void
        {
            // 可在此添加登录后的额外校验逻辑,比如账号过期等
        }
    }
    
  3. 在security.yaml中配置启用UserChecker
    在main防火墙配置中添加user_checker项:

    firewalls:
        main:
            # ... 已有配置
            user_checker: App\Security\UserChecker
    
  4. 在EasyAdmin中添加封禁/解封操作(可选)
    可以在User的CRUD控制器中添加自定义按钮,让管理员快速管理用户封禁状态:

    // src/Controller/Admin/UserCrudController.php
    use EasyCorp\Bundle\EasyAdminBundle\Config\Action;
    use EasyCorp\Bundle\EasyAdminBundle\Config\Actions;
    use EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext;
    use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
    use Symfony\Component\HttpFoundation\RedirectResponse;
    
    class UserCrudController extends AbstractCrudController
    {
        // ... 已有方法
    
        public function configureActions(Actions $actions): Actions
        {
            $toggleBlock = Action::new('toggleBlock', '封禁/解封')
                ->linkToCrudAction('toggleBlockAction');
    
            return $actions
                ->add(Action::INDEX, $toggleBlock)
                ->add(Action::DETAIL, $toggleBlock);
        }
    
        public function toggleBlockAction(AdminContext $context): RedirectResponse
        {
            /** @var \App\Entity\User $user */
            $user = $context->getEntity()->getInstance();
            $user->setIsBlocked(!$user->isBlocked());
            $this->getDoctrine()->getManager()->flush();
    
            $this->addFlash('success', sprintf('用户%s已%s', $user->getEmail(), $user->isBlocked() ? '封禁' : '解封'));
    
            return $this->redirect($this->generateUrl('admin', [
                'crudAction' => 'index',
                'entityFqcn' => \App\Entity\User::class,
            ]));
        }
    }
    

配置完成后,被封禁的用户尝试登录时会直接抛出LockedException,Symfony会自动跳转至登录页面并显示错误提示;管理员则可以在EasyAdmin后台便捷地管理用户的封禁状态。

内容的提问来源于stack exchange,提问作者yaboiii23

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 09:50:31