Silex:带有自定义验证器的用户表单
Silex: user form with custom authenticator
我正在尝试为我的 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;
}
}
谢谢!
虽然不是完整的答案,但这里有一些想法:
- 您真的应该尝试了解安全组件。对我来说最好的方法是创建一个简单的应用程序(2 个页面:登录表单和安全区域),然后逐步调试。我也很喜欢这个演讲:https://www.youtube.com/watch?v=C1y6fxetP5k&list=PLo7mBDsRHu12SbjRS_botIIdJ51zU0FxP&index=11
- 不,Symfony 和 Silex 的安全性并没有什么不同。主要区别在于配置部分
- 你的实现很正确,但是创建一个新的Application实例没有意义。您的服务只需要重定向 URL,您可以注入:
TokenAuthenticator.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);
}
//...
}
index.php
<?php
//...
$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'),
));
})->bind('login');
//...
$app['app.token_authenticator'] = function ($app) {
return new \CP\Classes\TokenAuthenticator(
$app['security.encoder_factory'],
$app['url_generator']->generate('login')
);
};
//...
我正在尝试为我的 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;
}
}
谢谢!
虽然不是完整的答案,但这里有一些想法:
- 您真的应该尝试了解安全组件。对我来说最好的方法是创建一个简单的应用程序(2 个页面:登录表单和安全区域),然后逐步调试。我也很喜欢这个演讲:https://www.youtube.com/watch?v=C1y6fxetP5k&list=PLo7mBDsRHu12SbjRS_botIIdJ51zU0FxP&index=11
- 不,Symfony 和 Silex 的安全性并没有什么不同。主要区别在于配置部分
- 你的实现很正确,但是创建一个新的Application实例没有意义。您的服务只需要重定向 URL,您可以注入:
TokenAuthenticator.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);
}
//...
}
index.php
<?php
//...
$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'),
));
})->bind('login');
//...
$app['app.token_authenticator'] = function ($app) {
return new \CP\Classes\TokenAuthenticator(
$app['security.encoder_factory'],
$app['url_generator']->generate('login')
);
};
//...