检查用户是否在不安全的路由上通过身份验证
Check if the user is authenticated on not secured route
我正在尝试使用 Silex 中的 symofny/security
包构建一个简单的登录,但我在身份验证检查方面遇到了一个小问题。
结构:
/
/login
/admin
/login_check
/logout
为了到达 /admin
路由,用户需要经过身份验证,如果没有,他将被重定向到 /login
表单,然后按照建议,询问 admin/login_check
用于身份验证(这都是由 symofny 的安全防火墙提供的)。
防火墙配置:
'security.firewalls' => array(
'login' => array(
'pattern' => '^/login$',
),
'admin' => array(
'pattern' => '^/admin',
'http' => true,
'form' => array(
'login_path' => '/login',
'check_path' => '/admin/login'
),
'logout' => array(
'logout_path' => '/admin/logout',
'invalidate_session' => true
),
'users' => ...
),
)
一切正常,但用户可以输入 /login
路由,即使他已经通过身份验证,这还不错,但我想避免这种情况。我厌倦了检查用户身份验证状态,但我想它不起作用,因为我在 /login
控制器上检查它,它不在网站的 "secured" 区域。
代码如下:
public function index(Request $request, Application $app)
{
if ($app['security.authorization_checker']->isGranted('ROLE_ADMIN')) {
return $app->redirect($app['url_generator']->generate('admin'));
}
return $app['twig']->render('login/index.twig', array(
'error' => $app['security.last_error']($request),
'last_username' => $app['session']->get('_security.last_username'),
));
}
这会抛出一个错误:The token storage contains no authentication token. One possible reason may be that there is no firewall configured for this URL.
所以,问题是,有没有办法使用 symfony/security
本机(没有任何绕过)来做到这一点?或者是否有可能在安全区域内创建 /login
路由,即使用户未登录(例如,为 GET 请求设置例外)也可以访问它,这将解决问题?
更新
我还为 /login
页面添加了带有选项 anonymous: true
的防火墙配置,这导致不再抛出错误,但是,当我登录 /admin
路线,方法 isGranted('ROLE_ADMIN')
导致 true
,而在 /login
路线上它导致 false
(我仍然在那里登录)。
您可以通过转储当前令牌轻松了解安全组件的行为。
public function index(Request $request, Application $app)
{
var_dump($application['security.token_storage']->getToken());
}
当你没有为登录页面设置anonymous
选项时(默认为false
):
null
当您将登录页面的 anonymous
选项设置为 true
时:
object(Symfony\Component\Security\Core\Authentication\Token\AnonymousToken)
private 'secret' => string 'login' (length=5)
private 'user' (Symfony\Component\Security\Core\Authentication\Token\AbstractToken) => string 'anon.' (length=5)
private 'roles' (Symfony\Component\Security\Core\Authentication\Token\AbstractToken) =>
array (size=0)
empty
private 'authenticated' (Symfony\Component\Security\Core\Authentication\Token\AbstractToken) => boolean true
private 'attributes' (Symfony\Component\Security\Core\Authentication\Token\AbstractToken) =>
array (size=0)
empty
以下示例描述了您在初始代码示例中出现错误的原因。
如何共享安全令牌?
要在多个防火墙之间共享安全令牌,您必须设置相同的 Firewall Context。
SecurityServiceProvider
为您使用模式 security.context_listener.<name>
声明的 protected 防火墙注册上下文侦听器。在您的示例中,它被注册为 security.context_listener.admin
。因此,您要使用的上下文被命名为 admin
.
防火墙上下文密钥也存储在会话中,因此每个使用它的防火墙都必须将其 stateless
选项设置为 false
。
此外,要在登录页面上调用身份验证,必须将 anonymous
选项设置为 true
'security.firewalls' => array(
'login' => array(
'context' => 'admin',
'stateless' => false,
'anonymous' => true,
'pattern' => '^/login$',
),
'admin' => array(
'context' => 'admin',
'stateless' => false,
'pattern' => '^/admin',
'http' => true,
'form' => array(
'login_path' => '/login',
'check_path' => '/admin/login'
),
'logout' => array(
'logout_path' => '/admin/logout',
'invalidate_session' => true
),
'users' => ...
),
)
更改后,如果您登录管理面板和登录页面,您将获得 Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken
的实例作为令牌,并且
Symfony\Component\Security\Core\Authentication\Token\AnonymousToken
如果您尚未登录。
因此,您可以使用 $app['security.authorization_checker']->isGranted('ROLE_ADMIN')
安全地检查权限,并在两个防火墙上获得相同的结果。
我正在尝试使用 Silex 中的 symofny/security
包构建一个简单的登录,但我在身份验证检查方面遇到了一个小问题。
结构:
/
/login
/admin
/login_check
/logout
为了到达 /admin
路由,用户需要经过身份验证,如果没有,他将被重定向到 /login
表单,然后按照建议,询问 admin/login_check
用于身份验证(这都是由 symofny 的安全防火墙提供的)。
防火墙配置:
'security.firewalls' => array(
'login' => array(
'pattern' => '^/login$',
),
'admin' => array(
'pattern' => '^/admin',
'http' => true,
'form' => array(
'login_path' => '/login',
'check_path' => '/admin/login'
),
'logout' => array(
'logout_path' => '/admin/logout',
'invalidate_session' => true
),
'users' => ...
),
)
一切正常,但用户可以输入 /login
路由,即使他已经通过身份验证,这还不错,但我想避免这种情况。我厌倦了检查用户身份验证状态,但我想它不起作用,因为我在 /login
控制器上检查它,它不在网站的 "secured" 区域。
代码如下:
public function index(Request $request, Application $app)
{
if ($app['security.authorization_checker']->isGranted('ROLE_ADMIN')) {
return $app->redirect($app['url_generator']->generate('admin'));
}
return $app['twig']->render('login/index.twig', array(
'error' => $app['security.last_error']($request),
'last_username' => $app['session']->get('_security.last_username'),
));
}
这会抛出一个错误:The token storage contains no authentication token. One possible reason may be that there is no firewall configured for this URL.
所以,问题是,有没有办法使用 symfony/security
本机(没有任何绕过)来做到这一点?或者是否有可能在安全区域内创建 /login
路由,即使用户未登录(例如,为 GET 请求设置例外)也可以访问它,这将解决问题?
更新
我还为 /login
页面添加了带有选项 anonymous: true
的防火墙配置,这导致不再抛出错误,但是,当我登录 /admin
路线,方法 isGranted('ROLE_ADMIN')
导致 true
,而在 /login
路线上它导致 false
(我仍然在那里登录)。
您可以通过转储当前令牌轻松了解安全组件的行为。
public function index(Request $request, Application $app)
{
var_dump($application['security.token_storage']->getToken());
}
当你没有为登录页面设置anonymous
选项时(默认为false
):
null
当您将登录页面的 anonymous
选项设置为 true
时:
object(Symfony\Component\Security\Core\Authentication\Token\AnonymousToken)
private 'secret' => string 'login' (length=5)
private 'user' (Symfony\Component\Security\Core\Authentication\Token\AbstractToken) => string 'anon.' (length=5)
private 'roles' (Symfony\Component\Security\Core\Authentication\Token\AbstractToken) =>
array (size=0)
empty
private 'authenticated' (Symfony\Component\Security\Core\Authentication\Token\AbstractToken) => boolean true
private 'attributes' (Symfony\Component\Security\Core\Authentication\Token\AbstractToken) =>
array (size=0)
empty
以下示例描述了您在初始代码示例中出现错误的原因。
如何共享安全令牌?
要在多个防火墙之间共享安全令牌,您必须设置相同的 Firewall Context。
SecurityServiceProvider
为您使用模式 security.context_listener.<name>
声明的 protected 防火墙注册上下文侦听器。在您的示例中,它被注册为 security.context_listener.admin
。因此,您要使用的上下文被命名为 admin
.
防火墙上下文密钥也存储在会话中,因此每个使用它的防火墙都必须将其 stateless
选项设置为 false
。
此外,要在登录页面上调用身份验证,必须将 anonymous
选项设置为 true
'security.firewalls' => array(
'login' => array(
'context' => 'admin',
'stateless' => false,
'anonymous' => true,
'pattern' => '^/login$',
),
'admin' => array(
'context' => 'admin',
'stateless' => false,
'pattern' => '^/admin',
'http' => true,
'form' => array(
'login_path' => '/login',
'check_path' => '/admin/login'
),
'logout' => array(
'logout_path' => '/admin/logout',
'invalidate_session' => true
),
'users' => ...
),
)
更改后,如果您登录管理面板和登录页面,您将获得 Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken
的实例作为令牌,并且
Symfony\Component\Security\Core\Authentication\Token\AnonymousToken
如果您尚未登录。
因此,您可以使用 $app['security.authorization_checker']->isGranted('ROLE_ADMIN')
安全地检查权限,并在两个防火墙上获得相同的结果。