使用simple_form身份验证器的Symfony2 + FOS [英] Symfony2 + FOS using simple_form authenticator

查看:107
本文介绍了使用simple_form身份验证器的Symfony2 + FOS的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用 FriendsOfSymfony UserBundle .当我将防火墙中的所有内容都设置为form_login时,它可以工作,但是如果我将其设置为simple_form,以使用自定义身份验证器,即使帐户已锁定或已禁用,我也可以登录.我想检查用户是否来自正确的IP,这就是为什么我创建了自定义身份验证器,但是似乎某些来自FOS的身份验证没有以这种方式处理.如何在自定义身份验证器上使用simple_form,同时仍保持FOS UserBundle的全部功能?

I use FriendsOfSymfony UserBundle. It works when I set everything in firewall as form_login, but if I set it to simple_form to use Custom Authenticator then it let's me login even if the account is locked or disabled. I want to check if the user comes from the correct IP, that's why I created the custom authenticator, but it seems that some authentication coming from FOS is not processed this way. How can I use simple_form with custom authenticator while still keeping full functionality of FOS UserBundle?

除了标准以外,还有其他方法可以实现其他身份验证吗?也许我做错了什么?我知道我可以更正身份验证器的代码以检查是否已锁定/启用,但是我发现-因为它实际上已经在FOS中完成-为什么我应该这么做?

Is there some other way I can achieve some other authentication than just the standard? Maybe I'm doing something wrong? I know I can correct this code of my authenticator to check for locked/enabled etc, but I figured - since it's actually already done in FOS - why should I?

另外,我注意到当我使用simple_form时,不会调用类Symfony\Component\Security\Core\User\UserChecker的方法.

Also, I noticed that when I use simple_form the methods of class Symfony\Component\Security\Core\User\UserChecker aren't being called.

下面是我的身份验证器和security.yml的代码:

Below is my code of authenticator and 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);
    }

}

推荐答案

我遇到了同样的问题.这是我解决的方法.

I was facing the same issue. Here is how I solved it.

您必须从Authenticator中的authenticateToken()方法中调用UserChecker类的checkPreAuth()和checkPostAuth()方法.

You must call checkPreAuth() and checkPostAuth() methods of your UserChecker class from within the authenticateToken() method in your Authenticator.

这是通过以下方式完成的:

That is done this way:

1)配置user_checker服务:

1) Configure the user_checker service:

services:
    app.user_checker:
        class: AppBundle\Security\UserChecker

2)将增强剂配置为服务并注入user_checker服务:

2) Configure the autenticator as a service and inject the user_checker service:

services:
    app.my_authenticator:
        class:     AppBundle\Security\MyAuthenticator
        arguments: ["@app.user_checker", "@security.password_encoder"]

3)现在,您可以在authenticateToken()上调用checkPreAuth()和checkPostAuth()

3) Now you can call checkPreAuth() and checkPostAuth() on authenticateToken()

无论如何,我认为symfony方法是正确的方法,因为在我的情况下,y需要在simple_form和login_form中执行不同的检查.

Anyway I think symfony approach is the right one, because in my case y needed to perform different checks in simple_form than in login_form.

这篇关于使用simple_form身份验证器的Symfony2 + FOS的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆