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

Symfony 6中如何限制某用户提供者访问路由,仅允许另一提供者访问?

解决Symfony中普通用户可访问Admin防火墙路由的问题

你的核心问题是:已登录的普通User实例能绕过admin防火墙的限制访问/admin路径,而你需要基于用户实例类型而非角色来控制权限。以下是直接可行的解决方案:

问题根源

当前的防火墙配置仅区分了登录入口和对应的用户提供者,但没有对已登录用户的实例类型做校验。当普通用户通过main防火墙登录后,访问/admin路径时,admin防火墙的lazy模式会复用已有的认证上下文,而没有验证用户是否是AdminUser实例,导致权限绕过。


方案1:用访问控制规则直接校验用户实例(最简方案)

无需自定义认证器,直接在security.yaml中添加access_control规则,强制校验访问/admin路径的用户类型:

1. 基础配置

在你的安全配置末尾添加:

security:
    # ... 已有的providers、firewalls配置 ...
    access_control:
        # 仅允许AdminUser实例访问/admin下的所有路径
        - { path: ^/admin, allow_if: "is_instance_of(user, App\\Entity\\AdminUser)" }

2. 优化登录页访问控制

如果需要允许未登录用户访问/admin/login,同时阻止已登录的普通用户进入该页面,调整规则为:

access_control:
        # 未登录用户或AdminUser可访问登录页
        - { path: ^/admin/login, allow_if: "is_anonymous() or is_instance_of(user, App\\Entity\\AdminUser)" }
        # 其他/admin路径仅允许AdminUser访问
        - { path: ^/admin, allow_if: "is_instance_of(user, App\\Entity\\AdminUser)" }

方案2:自定义认证器(复杂场景适用)

如果需要更复杂的认证逻辑(比如额外的身份校验、日志记录等),可以通过自定义认证器在认证阶段直接校验用户实例类型:

1. 创建AdminAuthenticator类

// src/Security/AdminAuthenticator.php
namespace App\Security;

use App\Entity\AdminUser;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Credentials\PasswordCredentials;
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
use Symfony\Component\Security\Http\Util\TargetPathTrait;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;

class AdminAuthenticator extends AbstractAuthenticator
{
    use TargetPathTrait;

    public function __construct(private UrlGeneratorInterface $urlGenerator)
    {
    }

    public function supports(Request $request): ?bool
    {
        // 仅处理admin登录的POST请求
        return $request->getPathInfo() === '/admin/login' && $request->isMethod('POST');
    }

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

        return new Passport(
            new UserBadge($email),
            new PasswordCredentials($password)
        );
    }

    public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
    {
        // 跳转至预设的目标路径或admin首页
        if ($targetPath = $this->getTargetPath($request->getSession(), $firewallName)) {
            return new RedirectResponse($targetPath);
        }

        return new RedirectResponse($this->urlGenerator->generate('admin_home'));
    }

    public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
    {
        // 记录错误信息并跳转回登录页
        $request->getSession()->set('security.login_error', $exception);
        return new RedirectResponse($this->urlGenerator->generate('admin_app_login'));
    }

    public function checkCredentials($credentials, UserInterface $user): bool
    {
        // 强制校验用户是否为AdminUser实例
        if (!$user instanceof AdminUser) {
            throw new CustomUserMessageAuthenticationException('仅管理员账号可登录此后台');
        }

        // 调用默认密码校验逻辑
        return password_verify($credentials, $user->getPassword());
    }
}

2. 在防火墙中配置自定义认证器

修改security.yaml的admin防火墙部分,添加自定义认证器:

admin:
    lazy: true
    pattern: ^/admin
    provider: admin_user_provider
    custom_authenticators:
        - App\Security\AdminAuthenticator
    form_login:
        login_path: admin_app_login
        check_path: admin_app_login
        username_parameter: _email
        password_parameter: _password
        default_target_path: admin_home
    logout:
        path: admin_app_logout
        target: admin_app_login

内容的提问来源于stack exchange,提问作者Чарльз Буковски

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 16:17:07