在会话到期时响应 HTTP_UNAUTHORIZED/Redirect
Responding with HTTP_UNAUTHORIZED/Redirect on session expiration
在我的应用程序中,我在 routes.php 文件中定义了一个 before()
挂钩:
$app->before(function(Request $request) use($app) {
$authAnon = $app['security']->isGranted('IS_AUTHENTICATED_ANONYMOUSLY');
if(!$request->getSession()->get('username') && $authAnon) {
if($request->isXmlHttpRequest()) {
// return 401/HTTP_UNAUTHORIZED response
$response = new Response();
$response->setStatusCode(Response::HTTP_UNAUTHORIZED);
$response->headers->set('Reason', 'SESSION_EXPIRED');
$response->headers->set('WWW-Authenticate', 'MyAuthScheme realm="app:login"');
return $response;
}
return new RedirectResponse('login', 301);
}
}
但这导致 $app['security']
不是 found/defined:
InvalidArgumentException in Container.php line 96: Identifier "security" is not defined.
我的安全设置如下所示:
$app->register(new Silex\Provider\SecurityServiceProvider(), array(
'security.firewalls' => array(
'login' => array(
'pattern' => '^/login$',
),
'secured' => array(
'pattern' => '^.*$',
'form' => array('login_path' => '/login', 'check_path' => '/login_check'),
'logout' => array('logout_path' => '/logout', 'invalidate_session' => true),
'users' => array(
'admin' => array('ROLE_ADMIN', 'hashed_pwd'),
'user' => array('ROLE_USER', 'hashed_pwd'),
),
),
)
));
$app['security.role_hierarchy'] = array(
'ROLE_ADMIN' => array('ROLE_USER'),
);
$app['security.access_rules'] = array(
array('^/admin', 'ROLE_ADMIN'),
array('^.*$', ['ROLE_USER']),
);
会话和安全提供程序的注册顺序如下所示:
$config_path = __DIR__.'/../app/config/';
require_once $config_path.'session.php';
require_once $config_path.'security.php';
require_once $config_path.'routes/routes.php';
$app->run();
我做错了什么?
编辑
请看看我下面的回答,看看我最终得到了什么。
security
服务已被弃用,将从 Silex 2.0 中删除。如果要检查用户的角色,则需要 security.authorization_checker
服务。
$authAnon = $app['security.authorization_checker']->isGranted('IS_AUTHENTICATED_ANONYMOUSLY');
由于您使用的是 master
(不稳定)版本,您需要注意这些事情,或者改用稳定版本。
我猜你现在使用的是 >= 2.6+ 的 Symfony 安全组件版本,所以根据 Silex docs 你不能直接使用服务安全性(如 $app['security']
) 并且您必须使用 授权检查器 服务 ($app['security.authorization_checker']
):
<?php
$app->before(function(Request $request) use($app) {
// This won't work with Symfony Security Component < 2.6
// $authAnon = $app['security']->isGranted('IS_AUTHENTICATED_ANONYMOUSLY');
// Under Symfony 2.6+
$authAnon = $app['security.authorization_checker']->isGranted('IS_AUTHENTICATED_ANONYMOUSLY');
// ...
}
这是我最后得出的结论:
if($request->headers->has('XHR-Request')) {
$isAuthFully = $app['security.authorization_checker']->isGranted('IS_AUTHENTICATED_FULLY');
if(!$isAuthFully and $request->get('_route') !== 'login') {
$response = new Response();
$response->setStatusCode(Response::HTTP_UNAUTHORIZED);
$response->headers->set('Login-Redirect', '');
$response->headers->set('WWW-Authenticate', 'AppAuthScheme realm="application:login"');
return $response;
}
}
我在客户端添加了自定义 XHR-Request
header:
angular.module('documentsCatalogApp', []).config(httpConfig);
httpConfig.$inject = ['$httpProvider'];
function httpConfig($httpProvider) {
$httpProvider.defaults.headers.common['XHR-Request'] = '';
}
Symfony 的 getRequest()->isXmlHttpRequest()
依赖于 X-Requested-With
header 可能会被浏览器剥离,至少我看过一篇关于Firefox的报道。
然后我添加了拦截器:
// mount the config / interceptor to your Angular application
// .config(xhrLoginRedirectInterceptorConfig)
// .factory('xhrLoginRedirectInterceptor', xhrLoginRedirectInterceptor)
xhrLoginRedirectInterceptorConfig.$inject = ['$httpProvider'];
function xhrLoginRedirectInterceptorConfig($httpProvider) {
$httpProvider.interceptors.push('xhrLoginRedirectInterceptor');
}
xhrLoginRedirectInterceptor.$inject = ['$q', '$window'];
function xhrLoginRedirectInterceptor($q, $window) {
return {
request: function(request) { return request; },
response: function(response) { return response; },
responseError: function(response) {
var headersList = response.headers();
var loginRequired = headersList && headersList.hasOwnProperty('Login-Redirect');
if(response.status === 401 && loginRequired) {
var url = "http://" + $window.location.host + baseUrl + "/login";
$window.location.href = url;
}
return $q.reject(response);
}
}
}
参考资料
在我的应用程序中,我在 routes.php 文件中定义了一个 before()
挂钩:
$app->before(function(Request $request) use($app) {
$authAnon = $app['security']->isGranted('IS_AUTHENTICATED_ANONYMOUSLY');
if(!$request->getSession()->get('username') && $authAnon) {
if($request->isXmlHttpRequest()) {
// return 401/HTTP_UNAUTHORIZED response
$response = new Response();
$response->setStatusCode(Response::HTTP_UNAUTHORIZED);
$response->headers->set('Reason', 'SESSION_EXPIRED');
$response->headers->set('WWW-Authenticate', 'MyAuthScheme realm="app:login"');
return $response;
}
return new RedirectResponse('login', 301);
}
}
但这导致 $app['security']
不是 found/defined:
InvalidArgumentException in Container.php line 96: Identifier "security" is not defined.
我的安全设置如下所示:
$app->register(new Silex\Provider\SecurityServiceProvider(), array(
'security.firewalls' => array(
'login' => array(
'pattern' => '^/login$',
),
'secured' => array(
'pattern' => '^.*$',
'form' => array('login_path' => '/login', 'check_path' => '/login_check'),
'logout' => array('logout_path' => '/logout', 'invalidate_session' => true),
'users' => array(
'admin' => array('ROLE_ADMIN', 'hashed_pwd'),
'user' => array('ROLE_USER', 'hashed_pwd'),
),
),
)
));
$app['security.role_hierarchy'] = array(
'ROLE_ADMIN' => array('ROLE_USER'),
);
$app['security.access_rules'] = array(
array('^/admin', 'ROLE_ADMIN'),
array('^.*$', ['ROLE_USER']),
);
会话和安全提供程序的注册顺序如下所示:
$config_path = __DIR__.'/../app/config/';
require_once $config_path.'session.php';
require_once $config_path.'security.php';
require_once $config_path.'routes/routes.php';
$app->run();
我做错了什么?
编辑
请看看我下面的回答,看看我最终得到了什么。
security
服务已被弃用,将从 Silex 2.0 中删除。如果要检查用户的角色,则需要 security.authorization_checker
服务。
$authAnon = $app['security.authorization_checker']->isGranted('IS_AUTHENTICATED_ANONYMOUSLY');
由于您使用的是 master
(不稳定)版本,您需要注意这些事情,或者改用稳定版本。
我猜你现在使用的是 >= 2.6+ 的 Symfony 安全组件版本,所以根据 Silex docs 你不能直接使用服务安全性(如 $app['security']
) 并且您必须使用 授权检查器 服务 ($app['security.authorization_checker']
):
<?php
$app->before(function(Request $request) use($app) {
// This won't work with Symfony Security Component < 2.6
// $authAnon = $app['security']->isGranted('IS_AUTHENTICATED_ANONYMOUSLY');
// Under Symfony 2.6+
$authAnon = $app['security.authorization_checker']->isGranted('IS_AUTHENTICATED_ANONYMOUSLY');
// ...
}
这是我最后得出的结论:
if($request->headers->has('XHR-Request')) {
$isAuthFully = $app['security.authorization_checker']->isGranted('IS_AUTHENTICATED_FULLY');
if(!$isAuthFully and $request->get('_route') !== 'login') {
$response = new Response();
$response->setStatusCode(Response::HTTP_UNAUTHORIZED);
$response->headers->set('Login-Redirect', '');
$response->headers->set('WWW-Authenticate', 'AppAuthScheme realm="application:login"');
return $response;
}
}
我在客户端添加了自定义 XHR-Request
header:
angular.module('documentsCatalogApp', []).config(httpConfig);
httpConfig.$inject = ['$httpProvider'];
function httpConfig($httpProvider) {
$httpProvider.defaults.headers.common['XHR-Request'] = '';
}
Symfony 的 getRequest()->isXmlHttpRequest()
依赖于 X-Requested-With
header 可能会被浏览器剥离,至少我看过一篇关于Firefox的报道。
然后我添加了拦截器:
// mount the config / interceptor to your Angular application
// .config(xhrLoginRedirectInterceptorConfig)
// .factory('xhrLoginRedirectInterceptor', xhrLoginRedirectInterceptor)
xhrLoginRedirectInterceptorConfig.$inject = ['$httpProvider'];
function xhrLoginRedirectInterceptorConfig($httpProvider) {
$httpProvider.interceptors.push('xhrLoginRedirectInterceptor');
}
xhrLoginRedirectInterceptor.$inject = ['$q', '$window'];
function xhrLoginRedirectInterceptor($q, $window) {
return {
request: function(request) { return request; },
response: function(response) { return response; },
responseError: function(response) {
var headersList = response.headers();
var loginRequired = headersList && headersList.hasOwnProperty('Login-Redirect');
if(response.status === 401 && loginRequired) {
var url = "http://" + $window.location.host + baseUrl + "/login";
$window.location.href = url;
}
return $q.reject(response);
}
}
}
参考资料