安全系统确实可能不堪重负,很难知道从哪里开始。我怀疑那里可能已经有 ldap 包(提示),但制作自己的包更有趣。
了解标准 form_login 防火墙是如何实现的会很有帮助。身份验证提供程序简化为只有两种方法:
namespace Symfony\Component\Security\Core\Authentication\Provider;
class DaoAuthenticationProvider extends UserAuthenticationProvider
{
private $encoderFactory;
private $userProvider;
protected function retrieveUser($username, UsernamePasswordToken $token)
{
try {
$user = $this->userProvider->loadUserByUsername($username);
protected function checkAuthentication(UserInterface $user, UsernamePasswordToken $token)
{
if (!$this->encoderFactory->getEncoder($user)->isPasswordValid($user->getPassword(), $presentedPassword, $user->getSalt())) {
throw new BadCredentialsException('The presented password is invalid.');
这样就出现了一个登录表单,用户填写用户名和密码,按下登录按钮,form_login 防火墙拦截了 login_check 请求,做了各种奇妙的事情,但最终调用了 authenticationProvider.retrieverUser,后者又调用了 userProvider.loadUserByUsername。
然后,您的 ldap 用户提供程序将对用户名进行 ldap 搜索。如果什么也没找到,那么你抛出一个 UserNotFoundException。如果找到该用户,则包装任何有用的信息位并返回一个用户对象。此时密码无关紧要。
更神奇的事情发生了,最终 authenticationProvider.checkAuthentication 使用从您的用户提供程序返回的任何用户对象调用。此时您将使用您的 ldap 服务对用户进行身份验证(绑定)。用户在登录表单中输入的明文密码可通过 $presentedPassword 获得。
一旦你有一个经过身份验证的用户,事情就会变得有点模糊。您提到在本地数据库中缓存内容。您可能最终不得不重写 authenticationProvider.authenticate 方法以正确构建经过身份验证的令牌。你可能需要训练你的 userProvider.refreshUser 来和你的本地缓存对话。在进行 ldap 搜索之前,您甚至可能需要让 userProvider.loadUserByUsername 检查您的本地缓存。这些都是特定于您的设计的细节。
您可以使用参数密钥 security.authentication.provider.dao.class 从 form_login 防火墙中指向您自己的身份验证提供程序类。反过来,这将使您无需构建完整的防火墙包即可运行大部分(可能全部)ldap 功能。
玩得开心。