首先简要解释一下我的任务。我正在使用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
用户管理员无论如何都可以毫无问题地登录。
我感谢任何帮助。如果有人认为我的整个方法都很糟糕并且知道更好的方法,那么请不要饶恕批评者。
我知道有FOSUserBundle和SonataUserBundle,但我更喜欢自定义用户提供程序,因为我不想膨胀实体Employee,因为我真的不需要所有这些属性,如password,salt,isLocked等。另外,我不认为在我的特定情况下配置SonataUserBundle会更简单。如果您仍然认为有更优雅的方式来完成我的任务,我会很高兴得到一个好的建议。
答案 0 :(得分:4)
您可以为每个防火墙配置用户检查程序,您的数据库用户提供程序实际上不是用户提供程序,因为它没有验证用户身份所需的所有信息(例如密码) ) 所以我要做的是,我会删除数据库用户提供程序并添加用户检查程序,用户检查程序的主要思想是在身份验证过程中添加其他检查,在您的情况下我们需要检查用户是否在雇员表是否
你需要做三件事来实现这个
实施UserCheckerInterface Symfony\Component\Security\Core\User\UserCheckerInterface
在checkPostAuth()
方法
将您的新用户检查器公开为服务
services:
app.employee_user_checker:
class: Path\To\Class\EmployeeUserChecker
更改防火墙配置以使用新的用户检查程序
security:
firewalls:
admin:
pattern: ^/admin
user_checker: app.employee_user_checker
#...