[英]Symfony2 + FOS using simple_form authenticator
我使用FriendsOfSymfony UserBundle 。 當我將防火牆中的所有內容都設置為form_login
,它可以工作,但是如果我將其設置為simple_form
以使用Custom Authenticator,那么即使帳戶被鎖定或禁用,也讓我登錄。 我想檢查用戶是否來自正確的IP,這就是為什么我創建了自定義身份驗證器,但是似乎某些來自FOS的身份驗證沒有以這種方式處理。 如何在仍保留FOS UserBundle的全部功能的同時,將simple_form
與自定義身份驗證simple_form
一起使用?
除了標准以外,還有其他方法可以實現其他身份驗證嗎? 也許我做錯了什么? 我知道我可以更正身份驗證器的此代碼以檢查是否已鎖定/啟用等,但我認為-因為它實際上已經在FOS中完成-為什么我應該這樣做?
編輯:另外,我注意到當我使用simple_form
,不會調用Symfony\\Component\\Security\\Core\\User\\UserChecker
類的方法。
以下是我的authenticator和security.yml
代碼:
config.yml
services:
login_authenticator:
class: Forex\AlchemyBundle\Security\LoginAuthenticator
arguments: ["@security.encoder_factory"]
security.yml
security:
encoders:
FOS\UserBundle\Model\UserInterface: sha512
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: ROLE_ADMIN
providers:
fos_userbundle:
id: fos_user.user_provider.username_email
firewalls:
main:
pattern: ^/
simple_form:
authenticator: login_authenticator
provider: fos_userbundle
csrf_provider: form.csrf_provider
logout: true
anonymous: true
access_control:
- { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY } # To be removed
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/, role: ROLE_ADMIN }
- { path: ^/.*, roles: ROLE_USER }
LoginAuthenticator
<?php
namespace Forex\AlchemyBundle\Security;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Authentication\SimpleFormAuthenticatorInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Core\User\UserProviderInterface;
class LoginAuthenticator implements SimpleFormAuthenticatorInterface
{
private $encoderFactory;
public function __construct(EncoderFactoryInterface $encoderFactory)
{
$this->encoderFactory = $encoderFactory;
}
public function authenticateToken(TokenInterface $token, UserProviderInterface $userProvider, $providerKey)
{
try {
$user = $userProvider->loadUserByUsername($token->getUsername());
} catch (UsernameNotFoundException $e) {
throw new AuthenticationException('Invalid username or password');
}
$encoder = $this->encoderFactory->getEncoder($user);
$passwordValid = $encoder->isPasswordValid(
$user->getPassword(),
$token->getCredentials(),
$user->getSalt()
);
if ($passwordValid) {
$request = Request::createFromGlobals();
$current_ip = $request->server->get('REMOTE_ADDR');
$user->setLoggedIP($current_ip);
if (!$user->isValidIP()) {
throw new AuthenticationException(
"You cannot login from your location.",
100
);
}
return new UsernamePasswordToken(
$user,
$user->getPassword(),
$providerKey,
$user->getRoles()
);
} else {
// TODO: Check if there weren't too many tries to login
}
throw new AuthenticationException('Invalid username or password');
}
public function supportsToken(TokenInterface $token, $providerKey)
{
return $token instanceof UsernamePasswordToken
&& $token->getProviderKey() === $providerKey;
}
public function createToken(Request $request, $username, $password, $providerKey)
{
return new UsernamePasswordToken($username, $password, $providerKey);
}
}
我面臨着同樣的問題。 這是我解決的方法。
您必須從Authenticator中的authenticateToken()方法中調用UserChecker類的checkPreAuth()和checkPostAuth()方法。
這樣可以完成:
1)配置user_checker服務:
services:
app.user_checker:
class: AppBundle\Security\UserChecker
2)將autenticator配置為服務並注入user_checker服務:
services:
app.my_authenticator:
class: AppBundle\Security\MyAuthenticator
arguments: ["@app.user_checker", "@security.password_encoder"]
3)現在您可以在authenticateToken()上調用checkPreAuth()和checkPostAuth()
無論如何,我認為symfony方法是正確的方法,因為在我的情況下,y需要在simple_form中執行與login_form不同的檢查。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.