Silex:具有自定义身份验证器的用户表单

时间:2016-09-21 18:24:28

标签: php authentication symfony silex

我正在尝试为我的Silex应用程序构建自定义身份验证系统。

这个想法是所有身份验证都将由单独的服务完成。我花了一天时间试图进入Silex \ Symfony认证机制,但不能说我做得很好: - \ 我发现这个Custom Authentication System with Guard教程对我来说很基础。使用它作为地下室我开始采用它来满足我的需求。 它一直有效,直到我尝试添加 form 位。

目前我的主要问题是它没有(或者我不明白该怎么做)在尝试访问安全区域时重定向到登录URL。我通过将硬编码重定向放入 TokenAuthenticator-> start()方法找到了一种解决方法,但它对我来说真的很糟糕。此外,在这种情况下,在成功验证后,它不会重定向到最初请求的URL。

有人可以告诉我我的代码中有什么问题(除非完全理解机制如何工作;或者至少描述Silex身份验证流程(从请求安全URL到成功验证后重定向)?请记住,我对Symfony完全不熟悉,因此他们的手册对我来说并不是很有用。

我的代码:

的index.php

<?
// bootstrap stuff here...

use Symfony\Component\HttpFoundation\Request;

$app->get('/login', function(Request $request) use ($app) {
    return $app['twig']->render('login.twig', array(
        'error'         => $app['security.last_error']($request),
        'last_username' => $app['session']->get('_security.last_username'),
    ));
});

$app['app.token_authenticator'] = function ($app) {
    return new \CP\Classes\TokenAuthenticator($app['security.encoder_factory']);
};

$app['security.firewalls'] = array(
    'secured' => array(
        'pattern' => '^/safe/',
        'form' => array('login_path' => '/login', 'check_path' => '/safe/login_check'),
        'logout' => array('logout_path' => '/safe/logout', 'invalidate_session' => true),
        'guard' => array(
            'authenticators' => array(
                'app.token_authenticator'
            ),
        ),
        'users' => function () use ($app) {
            return new \CP\Classes\OMSUserProvider($app);
        },
    ),
);

$app->register( new Silex\Provider\SecurityServiceProvider() );

// blablabla 
$app->run();

TokenAuthenticator.php

<?php

namespace CP\Classes;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Guard\AbstractGuardAuthenticator;

class TokenAuthenticator extends AbstractGuardAuthenticator {
    private $encoderFactory;

    public function __construct( EncoderFactoryInterface $encoderFactory ) {
        $this->encoderFactory = $encoderFactory;
    }

    public function getCredentials( Request $request ) {
        $username = $request->request->get('_username');
        $request->getSession()->set(Security::LAST_USERNAME, $username);
        $password = $request->request->get('_password');

        return array(
            'username' => $username,
            'password' => $password
        );
    }

    public function getUser( $credentials, UserProviderInterface $userProvider ) {
        return $userProvider->loadUserByUsername( $credentials['username'] );
    }

    public function checkCredentials( $credentials, UserInterface $user ) {
        $res = json_decode(file_get_contents('http://127.0.0.1:83/auth.php?u='.$user->getUsername().'&p='.$credentials['password']));

        return $res->result;
    }

    public function onAuthenticationSuccess( Request $request, TokenInterface $token, $providerKey ) {
        return;
    }

    public function onAuthenticationFailure( Request $request, AuthenticationException $exception ) {
        $data = [ 'message' => strtr( $exception->getMessageKey(), $exception->getMessageData() )];

        return new JsonResponse( $data, 403 );
    }

    /**
     * Called when authentication is needed, but it's not sent
     */
    public function start( Request $request, AuthenticationException $authException = null ) {
//      Mentioned hardcoded redirect
//      $app = new \Silex\Application();
//      return $app->redirect('/login', 401);

        $data = [ // you might translate this message
                  'message' => 'Authentication Required', ];

        return new JsonResponse( $data, 401 );
    }

    public function supportsRememberMe() {
        return false;
    }
}

谢谢!

1 个答案:

答案 0 :(得分:2)

虽然不是一个完整的答案,但这里有一些想法:

  1. 您应该尝试了解安全组件。对我来说最好的方法是创建一个简单的应用程序(2页:登录表单和安全区域),并通过一步一步的调试器。我真的很喜欢这个演讲:https://www.youtube.com/watch?v=C1y6fxetP5k&list=PLo7mBDsRHu12SbjRS_botIIdJ51zU0FxP&index=11
  2. 不,Symfony和Silex的安全性并没有那么不同。主要区别在于配置部分
  3. 您的实现是完全正确的,但创建一个新的Application实例是没有意义的。您的服务只需要重定向URL,您可以注入:
  4. <强> TokenAuthenticator.php

    volumes: "{{ [{'device_name': '/dev/sdb'},{'device_name': '/dev/sdc'}] | map('combine',vol_default) | list }}"
    

    <强>的index.php

    <?php
    
    //...
    use Symfony\Component\HttpFoundation\RedirectResponse;
    
    class TokenAuthenticator extends AbstractGuardAuthenticator
    {
        private $encoderFactory;
    
        private $login_url
    
        public function __construct(EncoderFactoryInterface $encoderFactory , $login_url = '/login')
        {
            $this->encoderFactory = $encoderFactory;
            $this->login_url = $login_url;
        }
    
        //...
    
        /**
         * Called when authentication is needed, but it's not sent
         */
        public function start(Request $request, AuthenticationException $authException = null)
        {
            return new RedirectResponse($this->login_url, 401);
        }
    
        //...
    }