[英]Symfony: Authenticate users against LDAP server, but allow login only if their username is in custom db table
首先簡要解釋一下我的任務。 我正在使用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都可以in_memory
登錄。
我感謝任何幫助。 如果有人認為我的整個方法都很糟糕並且知道更好的方法,那么請不要饒恕批評者。
我知道有FOSUserBundle和SonataUserBundle,但我更喜歡自定義用戶提供商,因為我不想膨脹實體Employee,因為我真的不需要所有這些屬性,如密碼,鹽,isLocked等。我也不喜歡我認為在我的特定情況下配置SonataUserBundle會簡單得多。 如果您仍然認為有更優雅的方式來完成這兩個捆綁包的任務,我將很高興得到一個好的建議。
您可以為每個防火牆配置用戶檢查程序,您的數據庫用戶提供程序實際上不是用戶提供程序,因為它沒有驗證用戶所需的所有信息(例如密碼)所以我要做的是,我會刪除數據庫用戶提供程序並添加用戶檢查程序,用戶檢查程序的主要思想是在身份驗證過程中添加其他檢查,在您的情況下我們需要檢查用戶是否在employee表中
你需要做三件事來實現這個
實現UserCheckerInterface Symfony\\Component\\Security\\Core\\User\\UserCheckerInterface
在checkPostAuth()
方法中檢查用戶是否在employee表中
將您的新用戶檢查器作為服務公開
services:
app.employee_user_checker:
class: Path\To\Class\EmployeeUserChecker
更改防火牆配置以使用新的用戶檢查程序
security:
firewalls:
admin:
pattern: ^/admin
user_checker: app.employee_user_checker
#...
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.