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服务
封装自定义服务,确保注入时已完成绑定:
- 创建自定义服务类:
// 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; } }
- 在
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)%'
- 控制器中使用:
<?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
相关产品推荐
相关产品推荐

