首先简要说明一下我的任务。我正在使用Symfony 2.8,并具有一个带有REST API和SonataAdminBundle的应用程序。网站的访问者可以通过REST API将某些数据发布到数据库中。特定的一组员工应该通过管理区域来管理这些数据。
对管理区域的访问应使用用户名和密码进行保护。存在Employee
具有属性的实体username
,但没有密码。应当针对LDAP服务器进行身份验证,但是对管理区域的访问应仅限于实体中存在的那些员工,Employee
即引用数据库表。
对于LDAP身份验证,我正在使用Symfony 2.8中的新LDAP组件。
除此之外,还应该有一个管理员帐户作为in_memory
用户。
这就是我现在所拥有的:
app/config/services.yml
services:
app.ldap:
class: Symfony\Component\Ldap\LdapClient
arguments: ["ldaps://ldap.uni-rostock.de"]
app.db_user_provider:
class: AppBundle\Security\DbUserProvider
arguments: ["@doctrine.orm.entity_manager"]
app/config/security.yml
security:
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: [ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
providers:
chain_provider:
chain:
providers: [db_user, app_users]
in_memory:
memory:
users:
admin: { password: adminpass, roles: 'ROLE_ADMIN' }
app_users:
ldap:
service: app.ldap
base_dn: ou=people,o=uni-rostock,c=de
search_dn: uid=testuser,ou=people,o=uni-rostock,c=de
search_password: testpass
filter: (uid={username})
default_roles: ROLE_USER
db_user:
id: app.db_user_provider
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
admin:
anonymous: true
pattern: ^/
form_login_ldap:
provider: chain_provider
service: app.ldap
dn_string: "uid={username},ou=people,o=uni-rostock,c=de"
check_path: /login_check
login_path: /login
form_login:
provider: in_memory
check_path: /login_check
login_path: /login
logout:
path: /logout
target: /
access_control:
- { path: ^/admin, roles: ROLE_USER }
encoders:
Symfony\Component\Security\Core\User\User: plaintext
AppBundle\Entity\Employee: bcrypt
src/AppBundle/Entity/Employee.php
namespace AppBundle\Entity;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\EquatableInterface;
use Doctrine\ORM\Mapping as ORM;
class Employee implements UserInterface, EquatableInterface
{
// other properties
private $username;
// getters and setters for the other properties
public function getUsername()
{
return $this->username;
}
public function getRoles()
{
return array('ROLE_USER');
}
public function getPassword()
{
return null;
}
public function getSalt()
{
return null;
}
public function eraseCredentials()
{
}
public function isEqualTo(UserInterface $user)
{
if (!$user instanceof Employee) {
return false;
}
if ($this->username !== $user->getUsername()) {
return false;
}
return true;
}
}
src/AppBundle/Security/DbUserProvider.php
<?php
namespace AppBundle\Security;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
use Doctrine\ORM\EntityManager;
use AppBundle\Entity\Employee;
class DbUserProvider implements UserProviderInterface
{
private $em;
public function __construct(EntityManager $em)
{
$this->em = $em;
}
public function loadUserByUsername($username)
{
$repository = $this->em->getRepository('AppBundle:Employee');
$user = $repository->findOneByUsername($username);
if ($user) {
return new Employee();
}
throw new UsernameNotFoundException(
sprintf('Username "%s" does not exist.', $username)
);
}
public function refreshUser(UserInterface $user)
{
if (!$user instanceof Employee) {
throw new UnsupportedUserException(
sprintf('Instances of "%s" are not supported.', get_class($user))
);
}
return $this->loadUserByUsername($user->getUsername());
}
public function supportsClass($class)
{
return $class === 'AppBundle\Entity\Employee';
}
}
针对LDAP的身份验证就像一个超级按钮。当数据库中的员工尝试登录时,他/她将被重定向到主页('/'),并且登录失败。不在数据库中的所有其他用户可以顺利登录。
那与我想要的恰恰相反!
如果我这样链接提供者:
chain_provider:
chain:
providers: [app_users, db_user]
那么该方法loadUserByUsername
甚至不会被调用,并且所有用户都可以登录,数据库中的用户和非数据库中的用户都可以登录。
该in_memory
admin用户可以登录没有在任何情况下的一个问题。
感谢您的帮助。如果有人认为我的整体方法不好,并且知道更好的方法,请不要批评家。
我知道有FOSUserBundle和SonataUserBundle,但是我更喜欢自定义用户提供程序,因为我不想want肿实体Employee,因为我真的不需要所有那些属性,例如密码,salt,isLocked等。我认为在我的特殊情况下配置SonataUserBundle不会简单得多。如果您仍然认为使用这两个捆绑包可以找到一种更优雅的方式来完成我的任务,我将不胜感激获得良好的建议。
您可以为每个防火墙配置用户检查器,您的数据库用户提供者并不是真正的用户提供者,因为它不具备验证用户身份所需的所有信息(例如密码),因此我要做的是,我将删除db用户提供者并添加一个用户检查器,该用户检查器的主要思想是在身份验证过程中添加其他检查,在这种情况下,我们需要检查用户是否在employee表中
您需要做三件事来实现这一目标
实现UserCheckerInterface Symfony\Component\Security\Core\User\UserCheckerInterface
检查用户是否在employee表中或不在checkPostAuth()
方法中
将您的新用户检查器公开为服务
services:
app.employee_user_checker:
class: Path\To\Class\EmployeeUserChecker
更改防火墙配置以使用新的用户检查器
security:
firewalls:
admin:
pattern: ^/admin
user_checker: app.employee_user_checker
#...
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句