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

Symfony无法保持LDAP连接,执行查询时提示未绑定连接

Symfony LDAP认证后无法保持连接,查询时报错"Query execution is not possible without binding the connection first."

配置信息

已在security.yaml中配置LDAP认证,内容如下:

providers:
    ldap:
        ldap:
            service: Symfony\Component\Ldap\Ldap
            base_dn: 'DC=DOMAIN,DC=COM'
            search_dn: 'DOMAIN\ADMIN'            
            search_password: 'PASSWORD'
            default_roles: ROLE_USER
            uid_key: sAMAccountName

firewalls:
    dev:
        pattern: ^/(_(profiler|wdt)|css|images|js)/
        security: false
    main:
        lazy: true
        provider: ldap
        form_login_ldap:
            service: Symfony\Component\Ldap\Ldap
            login_path: app_login
            check_path : app_login
            dn_string: 'DOMAIN\{user_identifier}'
            enable_csrf: true
            username_parameter: login[username]
            password_parameter: login[password]
        logout:
            path: "logout"

问题现象

LDAP账号可正常登录,但在控制器中尝试获取账号属性时,抛出错误:

Query execution is not possible without binding the connection first.

控制器代码:

<?php

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Ldap\Ldap;


class HomeController extends AbstractController
{
    #[Route('/home', name: 'app_home')]
    public function index(Request $request, Ldap $ldap): Response
    {
        $this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY');
        $user = $this->getUser()->getUserIdentifier();
        $query = $ldap->query('dc=doadei,dc=wan', '(&(objectClass=user)(sAMAccountName=' . $user . '))');
        $result = $query->execute()->toArray();
        dump($result);
   
        return $this->render('home/index.html.twig', [
            'controller_name' => 'HomeController',
        ]);
    }
}

临时可行方案

手动创建并绑定LDAP连接后可正常查询:

$ldap = Ldap::create('my_ldap', [
        'host' => 'DOMAIN.COM',
        "port" => 389,
        'encryption' => 'none',
        'version' => 3,
        'debug' => true,
        "referrals" => false
    ]);
$ldap->bind("DOMAIN\ADMIN", "PASSWORD");

$query = $ldap->query('dc=DOMAIN,dc=COM', '(&(objectClass=user)(sAMAccountName=' . $user . '))');
$result = $query->execute()->toArray();
dump($result);

连接状态验证

通过dump($ldap->getEntryManager())查看,连接确实未绑定:

Symfony\Component\Ldap\Adapter\ExtLdap\EntryManager {#545 ▼
  -connection: Symfony\Component\Ldap\Adapter\ExtLdap\Connection {#548 ▼
    #config: array:8 [▼
      "host" => "DOMAIN.COM"
      "version" => 3
      "encryption" => "none"
      "port" => 389
      "connection_string" => "ldap://DOMAIN.COM:389"
      "debug" => false
      "referrals" => false
      "options" => array:3 [▶]
    ]
    -bound: false
    -connection: null
  }
}

问题原因

Symfony注入的Ldap实例默认是每次请求都会生成新的未绑定实例,认证过程中使用的连接是临时创建用于验证用户身份的,不会自动复用或保持绑定状态供后续业务逻辑调用。

解决方案

方案1:配置LDAP服务自动绑定

在services.yaml中配置Ldap服务,初始化时自动完成绑定:

services:
    Symfony\Component\Ldap\Ldap:
        arguments: ['@Symfony\Component\Ldap\Adapter\ExtLdap\Adapter']
        calls:
            - method: bind
              arguments:
                  - '%env(LDAP_SEARCH_DN)%'
                  - '%env(LDAP_SEARCH_PASSWORD)%'
    Symfony\Component\Ldap\Adapter\ExtLdap\Adapter:
        arguments:
            - host: '%env(LDAP_HOST)%'
              port: '%env(LDAP_PORT)%'
              encryption: '%env(LDAP_ENCRYPTION)%'
              version: 3
              referrals: false

建议通过环境变量管理敏感信息,避免硬编码。

方案2:复用Security组件的LDAP连接

注入LdapUserProvider获取已配置的LDAP实例,必要时手动绑定:

<?php

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\User\LdapUserProvider;


class HomeController extends AbstractController
{
    #[Route('/home', name: 'app_home')]
    public function index(Request $request, LdapUserProvider $ldapUserProvider): Response
    {
        $this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY');
        $user = $this->getUser()->getUserIdentifier();
        
        $ldap = $ldapUserProvider->getLdap();
        // 检查连接是否已绑定,未绑定则手动绑定
        if (!$ldap->getAdapter()->getConnection()->isBound()) {
            $ldap->bind('DOMAIN\ADMIN', 'PASSWORD');
        }
        
        $query = $ldap->query('DC=DOMAIN,DC=COM', '(&(objectClass=user)(sAMAccountName=' . $user . '))');
        $result = $query->execute()->toArray();
        dump($result);
   
        return $this->render('home/index.html.twig', [
            'controller_name' => 'HomeController',
        ]);
    }
}

方案3:自定义LDAP服务

封装自定义服务,确保注入时已完成绑定:

  1. 创建自定义服务类:
// src/Service/LdapService.php
namespace App\Service;

use Symfony\Component\Ldap\Ldap;

class LdapService
{
    private Ldap $ldap;

    public function __construct(string $host, int $port, string $encryption, string $searchDn, string $searchPassword)
    {
        $this->ldap = Ldap::create('ext_ldap', [
            'host' => $host,
            'port' => $port,
            'encryption' => $encryption,
            'version' => 3,
            'referrals' => false,
        ]);
        $this->ldap->bind($searchDn, $searchPassword);
    }

    public function getLdap(): Ldap
    {
        return $this->ldap;
    }
}
  1. 在services.yaml中配置:
services:
    App\Service\LdapService:
        arguments:
            $host: '%env(LDAP_HOST)%'
            $port: '%env(LDAP_PORT)%'
            $encryption: '%env(LDAP_ENCRYPTION)%'
            $searchDn: '%env(LDAP_SEARCH_DN)%'
            $searchPassword: '%env(LDAP_SEARCH_PASSWORD)%'
  1. 控制器中使用:
<?php

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use App\Service\LdapService;


class HomeController extends AbstractController
{
    #[Route('/home', name: 'app_home')]
    public function index(Request $request, LdapService $ldapService): Response
    {
        $this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY');
        $user = $this->getUser()->getUserIdentifier();
        
        $ldap = $ldapService->getLdap();
        $query = $ldap->query('DC=DOMAIN,DC=COM', '(&(objectClass=user)(sAMAccountName=' . $user . '))');
        $result = $query->execute()->toArray();
        dump($result);
   
        return $this->render('home/index.html.twig', [
            'controller_name' => 'HomeController',
        ]);
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 06:25:00