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

Symfony 6:如何为自定义认证器指定用户提供者

解决多用户提供者与同一自定义认证器的匹配问题

方法1:通过Security配置传递指定用户提供者

Symfony会自动将每个配置的用户提供者注册为服务,服务ID格式为security.user.provider.concrete.你的提供者名称。你可以在security.yaml中为每个防火墙的认证器指定要注入的用户提供者服务:

修改security.yaml配置:

firewalls:
    admin_token:
        pattern: ^/admin/\w\w/login-by-token/
        provider: admin_users_token_provider
        custom_authenticators:
            - App\Security\Authenticators\TokenAuthenticator:
                user_provider: '@security.user.provider.concrete.admin_users_token_provider'
        context: admin
    customer_token:
        pattern: ^/\w\w/login-by-token/
        provider: customer_users_token_provider
        custom_authenticators:
            - App\Security\Authenticators\TokenAuthenticator:
                user_provider: '@security.user.provider.concrete.customer_users_token_provider'
        context: customer

保持TokenAuthenticator构造函数不变:

use Symfony\Component\Security\Core\User\UserProviderInterface;

class TokenAuthenticator extends AbstractAuthenticator
{
    const LOGIN_TOKEN_ROUTE_PARAM = 'loginToken';

    public function __construct(
        protected UserProviderInterface $userProvider
    ) {
        // 无需修改
    }

    // 其余方法保持不变
}

这种方式会让Symfony为每个防火墙创建独立的TokenAuthenticator实例,分别注入对应的用户提供者,确保请求对应路由时使用正确的提供者。

方法2:动态获取当前防火墙的用户提供者

如果不想维护多个认证器实例,可以通过Firewall配置动态获取当前请求对应的用户提供者:

修改TokenAuthenticator代码:

use Symfony\Bundle\SecurityBundle\Security\FirewallMap;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Exception\UserNotFoundException;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Core\User\UserBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;

class TokenAuthenticator extends AbstractAuthenticator
{
    const LOGIN_TOKEN_ROUTE_PARAM = 'loginToken';

    public function __construct(
        protected FirewallMap $firewallMap
    ) {
    }

    public function supports(Request $request): ?bool
    {
        return $request->get(self::LOGIN_TOKEN_ROUTE_PARAM) !== null;
    }

    public function authenticate(Request $request): Passport
    {
        // 获取当前请求对应的防火墙配置
        $firewallConfig = $this->firewallMap->getFirewallConfig($request);
        if (!$firewallConfig) {
            throw new \RuntimeException('当前请求无匹配的防火墙配置');
        }

        // 获取当前防火墙绑定的用户提供者
        $userProvider = $firewallConfig->getUserProvider();
        if (!$userProvider instanceof UserProviderInterface) {
            throw new \RuntimeException('当前防火墙未配置有效用户提供者');
        }

        $token = $request->get(self::LOGIN_TOKEN_ROUTE_PARAM);
        $user = $userProvider->loadUserByIdentifier($token);
        
        if (!$user->isActive() || $user->isDeleted()) {
            throw new UserNotFoundException();
        }

        return new SelfValidatingPassport(
            new UserBadge($token, [$userProvider, 'loadUserByIdentifier'])
        );
    }
}

这种方式无需修改security.yaml的认证器配置,通过FirewallMap动态匹配当前请求的防火墙,再获取对应的用户提供者,适合简化配置的场景。

注意事项

  • 方法1的优势是依赖注入逻辑清晰,每个防火墙对应独立的认证器实例,适合复杂权限场景;
  • 方法2更简洁,避免重复配置,但依赖FirewallMap服务,动态获取提供者;
  • Symfony自动生成的用户提供者服务ID格式固定为security.user.provider.concrete.提供者名称,请确保配置中引用的服务ID与你的提供者名称一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 06:03:29