如何更改 Silex 中的安全重定向行为?
How do I change security redirect behavior in Silex?
如果我向安全区域发出 AJAX 请求,它会发送 302 header,然后重定向到该请求中的登录页面。有没有办法将防火墙配置为只提供不同的 header 而不是重定向?这是我需要在 ->before
调用中处理的事情吗?或者更好的方法是覆盖身份验证入口点,如 Symfony security return 401 response instead of redirect 中所建议的那样?那是针对 Symfony 的,所以不确定 Silex 是否有更好的糖分。
试过这个和其他东西:
$app->register(new SecurityServiceProvider(), array(
'security.firewalls' => array(
'default' => array(
'pattern' => '^/',
'anonymous' => true,
'oauth' => array(
'failure_path' => '/login',
'with_csrf' => true
),
'logout' => array(
'logout_path' => '/logout',
'with_csrf' => true
),
)
),
));
$app['security.authentication.entry_point.default.oauth'] = $app->share(function ($app) {
return new AuthenticationEntryPointComponent();
});
$app['security.authentication.entry_point.default.form'] = $app->share(function ($app) {
return new AuthenticationEntryPointComponent();
});
default
是security.firewalls
中的键名。仍然收到 302。
我不得不四处挖掘这么多代码,但明白了:
我的控制器:
$app['security.entry_point.form._proto'] =$app->protect(function ($name, array $options) use ($app) {
return $app->share(function () use ($app, $options) {
$login_path = isset($options['login_path']) ? $options['login_path'] : '/login';
return new MyCustomClass($app['security.http_utils'], $login_path);
});
});
class:
namespace Yours;
use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Http\HttpUtils;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class MyCustomClass implements AuthenticationEntryPointInterface {
protected $_login_path = '/login';
protected $_http_tools;
/**
* @param string $loginPath The path to the login form
*/
public function __construct(HttpUtils $http_utils, $login_path = '') {
$this->_http_tools = $http_utils;
if ( $login_path ) {
$this->_login_path = $login_path;
}
}
/**
* {@inheritDoc}
*/
public function start(Request $request, AuthenticationException $authException = null) {
if ($request->isXmlHttpRequest()) {
$response = new Response(json_encode([]), 401);
$response->headers->set('Content-Type', 'application/json');
return $response;
}
return $this->_http_tools->createRedirectResponse($request, $this->_login_path);
}
}
我也遇到了这个问题,令我惊讶的是 SecurityServiceProvider
不支持防火墙配置中的 entry_point
选项(就像 Symfony 安全配置一样)。
我用不同的方式解决了它。我没有覆盖 security.entry_point.form._proto
,而是遵循 SecurityServiceProvider
内置身份验证工厂,在我的自定义服务提供商的 register()
中,我这样写:
$app['security.authentication_listener.factory.MY_CUSTOM_FIREWALL'] = $app->protect(function ($name, array $options) use ($app) {
$app['security.authentication_provider.'.$name.'.anonymous'] = $app['security.authentication_provider.anonymous._proto']($name);
$app['security.authentication_listener.'.$name.'.anonymous'] = $app['security.authentication_listener.anonymous._proto']($name, $options);
$app['security.entry_point.'.$name.'.MY_CUSTOM_FIREWALL'] = $app->share(function() use ($app) {
return new MyCustomFirewallEntryPoint($app['url_generator']);
});
return [
'security.authentication_provider.'.$name.'.anonymous',
'security.authentication_listener.'.$name.'.anonymous',
'security.entry_point.'.$name.'.MY_CUSTOM_FIREWALL',
'anonymous'
];
});
然后在安全配置中:
$app->register(new Silex\Provider\SecurityServiceProvider(), [
'security.firewalls' => [
// All other routes require valid user
'secured' => [
'pattern' => '^.*$',
'anonymous' => true,
// It will search for custom factory
'MY_CUSTOM_FIREWALL' => true
],
],
]);
如果我向安全区域发出 AJAX 请求,它会发送 302 header,然后重定向到该请求中的登录页面。有没有办法将防火墙配置为只提供不同的 header 而不是重定向?这是我需要在 ->before
调用中处理的事情吗?或者更好的方法是覆盖身份验证入口点,如 Symfony security return 401 response instead of redirect 中所建议的那样?那是针对 Symfony 的,所以不确定 Silex 是否有更好的糖分。
试过这个和其他东西:
$app->register(new SecurityServiceProvider(), array(
'security.firewalls' => array(
'default' => array(
'pattern' => '^/',
'anonymous' => true,
'oauth' => array(
'failure_path' => '/login',
'with_csrf' => true
),
'logout' => array(
'logout_path' => '/logout',
'with_csrf' => true
),
)
),
));
$app['security.authentication.entry_point.default.oauth'] = $app->share(function ($app) {
return new AuthenticationEntryPointComponent();
});
$app['security.authentication.entry_point.default.form'] = $app->share(function ($app) {
return new AuthenticationEntryPointComponent();
});
default
是security.firewalls
中的键名。仍然收到 302。
我不得不四处挖掘这么多代码,但明白了:
我的控制器:
$app['security.entry_point.form._proto'] =$app->protect(function ($name, array $options) use ($app) {
return $app->share(function () use ($app, $options) {
$login_path = isset($options['login_path']) ? $options['login_path'] : '/login';
return new MyCustomClass($app['security.http_utils'], $login_path);
});
});
class:
namespace Yours;
use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Http\HttpUtils;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class MyCustomClass implements AuthenticationEntryPointInterface {
protected $_login_path = '/login';
protected $_http_tools;
/**
* @param string $loginPath The path to the login form
*/
public function __construct(HttpUtils $http_utils, $login_path = '') {
$this->_http_tools = $http_utils;
if ( $login_path ) {
$this->_login_path = $login_path;
}
}
/**
* {@inheritDoc}
*/
public function start(Request $request, AuthenticationException $authException = null) {
if ($request->isXmlHttpRequest()) {
$response = new Response(json_encode([]), 401);
$response->headers->set('Content-Type', 'application/json');
return $response;
}
return $this->_http_tools->createRedirectResponse($request, $this->_login_path);
}
}
我也遇到了这个问题,令我惊讶的是 SecurityServiceProvider
不支持防火墙配置中的 entry_point
选项(就像 Symfony 安全配置一样)。
我用不同的方式解决了它。我没有覆盖 security.entry_point.form._proto
,而是遵循 SecurityServiceProvider
内置身份验证工厂,在我的自定义服务提供商的 register()
中,我这样写:
$app['security.authentication_listener.factory.MY_CUSTOM_FIREWALL'] = $app->protect(function ($name, array $options) use ($app) {
$app['security.authentication_provider.'.$name.'.anonymous'] = $app['security.authentication_provider.anonymous._proto']($name);
$app['security.authentication_listener.'.$name.'.anonymous'] = $app['security.authentication_listener.anonymous._proto']($name, $options);
$app['security.entry_point.'.$name.'.MY_CUSTOM_FIREWALL'] = $app->share(function() use ($app) {
return new MyCustomFirewallEntryPoint($app['url_generator']);
});
return [
'security.authentication_provider.'.$name.'.anonymous',
'security.authentication_listener.'.$name.'.anonymous',
'security.entry_point.'.$name.'.MY_CUSTOM_FIREWALL',
'anonymous'
];
});
然后在安全配置中:
$app->register(new Silex\Provider\SecurityServiceProvider(), [
'security.firewalls' => [
// All other routes require valid user
'secured' => [
'pattern' => '^.*$',
'anonymous' => true,
// It will search for custom factory
'MY_CUSTOM_FIREWALL' => true
],
],
]);