Symfony身份验证提供程序

时间:2015-06-09 13:03:59

标签: php symfony authentication ldap

我正在使用fr3d/ldap-bundle。如果他们不在db中,它会将我登录并从AD导入用户。没关系。

尽管AD用户我也有本地用户,这些用户都在我的数据库中。有一个特殊的列authType,它说明了如何通过LDAP或本机(FOS)对用户进行身份验证。我已经创建了自己的用户提供商:

public function chooseProviderForUsername($username)
{
    if($user->getAuthType() == User::LOGIN_LDAP) {
         $this->properProvider = $this->ldapUserProvider;
     } elseif($user->getAuthType() == User::LOGIN_NATIVE) {
         $this->properProvider = $this->fosUserProvider;
     } else {
         throw new InvalidArgumentException('Error');
     }
}

public function loadUserByUsername($username)
{
    return $this->chooseProviderForUsername($username)->loadUserByUsername($username);
}

问题:链提供商不是一个选项 - 它允许用户使用他的LDAP密码和本地密码登录!这是一个很大的安全问题。

是否有办法通过不同的身份验证提供程序登录用户,具体取决于db字段?

编辑:

我的security.yml:

 providers:
        fos_userbundle:
            id: fos_user.user_provider.username
        appbundle_user_provider:
            id: appbundle.user_provider
        fr3d_ldapbundle:
            id: fr3d_ldap.security.user.provider

    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        admin:
            pattern: ^/admin.*
            context: user
            fr3d_ldap:  ~
            form_login:
                provider: appbundle_user_provider
                csrf_provider: security.csrf.token_manager
                always_use_default_target_path: true
                default_target_path: admin_main
                login_path: /admin/login
                check_path: /admin/login_check
            logout:
                path:   /admin/logout
                target: /admin/login
            anonymous:    true

这是security.yml。此行fr3d_ldap: ~启用ldap捆绑包,该捆绑包授权ldap用户并将其保存到我的数据库中。没有它我无法授权它们,可能我必须编写自定义AuthenticationProvider。

4 个答案:

答案 0 :(得分:1)

我对ldap不是很熟悉,但我建议尝试完全手动登录

  $token = new UsernamePasswordToken($user, null, "firewallname", $user->getRoles());
  $securityContext = $this->container->get('security.context');
  $securityContext->setToken($token);

然后您可以自己手动执行检查,并根据检查结果决定在进行身份验证之前如何验证用户。例如,在执行此登录代码之前,请按用户名和密码运行查询,具体取决于您想要的db字段。

答案 1 :(得分:0)

您的方法似乎很好,但您应该检查您的方法的逻辑。 首先是这一个:

public function chooseProviderForUsername($username)
{
    if($user->getAuthType() == User::LOGIN_LDAP) {
         $this->properProvider = $this->ldapUserProvider;
     } elseif($user->getAuthType() == User::LOGIN_NATIVE) {
         $this->properProvider = $this->fosUserProvider;
     } else {
         throw new InvalidArgumentException('Error');
     }
}

您将$username作为参数传递给此方法,但随后使用$user对象,这在当前上下文中似乎未定义。 其次:

public function loadUserByUsername($username)
{
    return $this->chooseProviderForUsername($username)->loadUserByUsername($username);
}

因为chooseProviderForUsername方法实际上没有返回任何值,所以你无法以这种方式链接它。

我希望重构这些问题可以使您的提供商正常工作。

答案 2 :(得分:0)

好的,非常简短的回答,但我认为目前Symfony正在搜索任何旧用户提供商中的用户而不是那个特定用户想要的用户(这解释了整个用两个密码登录的东西)。解决方案应该是AppBundleUserProvider实施UserProviderInterface,从security.yml删除其他用户提供商,然后确保AppBundleUserProvider做的第一件事就是找出哪个用户提供商对于该用户是必需的,然后模仿UserProviderInterface中的每个方法。您可以根据用户名设置$this->realUP,然后将每个方法设置为仅返回$this->realUP->someMethod()

答案 3 :(得分:0)

我能想到的最简洁的方法是创建自己的ChainProvider class,只允许使用一个提供商和use the Dependency Injection Container to use yours登录。

您只需要覆盖捆绑包配置文件中的 security.user.provider.chain.clas 参数定义。